Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/widget/gtk/nsImageToPixbuf.cpp
Line
Count
Source (jump to first uncovered line)
1
/* vim:set sw=4 sts=4 et cin: */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include <gdk-pixbuf/gdk-pixbuf.h>
7
8
#include "nsImageToPixbuf.h"
9
10
#include "imgIContainer.h"
11
#include "mozilla/gfx/2D.h"
12
#include "mozilla/RefPtr.h"
13
14
using mozilla::gfx::DataSourceSurface;
15
using mozilla::gfx::SurfaceFormat;
16
17
NS_IMPL_ISUPPORTS(nsImageToPixbuf, nsIImageToPixbuf)
18
19
inline unsigned char
20
unpremultiply (unsigned char color,
21
               unsigned char alpha)
22
0
{
23
0
    if (alpha == 0)
24
0
        return 0;
25
0
    // plus alpha/2 to round instead of truncate
26
0
    return (color * 255 + alpha / 2) / alpha;
27
0
}
28
29
NS_IMETHODIMP_(GdkPixbuf*)
30
nsImageToPixbuf::ConvertImageToPixbuf(imgIContainer* aImage)
31
0
{
32
0
    return ImageToPixbuf(aImage);
33
0
}
34
35
GdkPixbuf*
36
nsImageToPixbuf::ImageToPixbuf(imgIContainer* aImage)
37
0
{
38
0
    RefPtr<SourceSurface> surface =
39
0
      aImage->GetFrame(imgIContainer::FRAME_CURRENT,
40
0
                       imgIContainer::FLAG_SYNC_DECODE);
41
0
42
0
    // If the last call failed, it was probably because our call stack originates
43
0
    // in an imgINotificationObserver event, meaning that we're not allowed request
44
0
    // a sync decode. Presumably the originating event is something sensible like
45
0
    // OnStopFrame(), so we can just retry the call without a sync decode.
46
0
    if (!surface)
47
0
      surface = aImage->GetFrame(imgIContainer::FRAME_CURRENT,
48
0
                                 imgIContainer::FLAG_NONE);
49
0
50
0
    NS_ENSURE_TRUE(surface, nullptr);
51
0
52
0
    return SourceSurfaceToPixbuf(surface,
53
0
                                 surface->GetSize().width,
54
0
                                 surface->GetSize().height);
55
0
}
56
57
GdkPixbuf*
58
nsImageToPixbuf::SourceSurfaceToPixbuf(SourceSurface* aSurface,
59
                                       int32_t aWidth,
60
                                       int32_t aHeight)
61
0
{
62
0
    MOZ_ASSERT(aWidth <= aSurface->GetSize().width &&
63
0
               aHeight <= aSurface->GetSize().height,
64
0
               "Requested rect is bigger than the supplied surface");
65
0
66
0
    GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
67
0
                                       aWidth, aHeight);
68
0
    if (!pixbuf)
69
0
        return nullptr;
70
0
71
0
    uint32_t destStride = gdk_pixbuf_get_rowstride (pixbuf);
72
0
    guchar* destPixels = gdk_pixbuf_get_pixels (pixbuf);
73
0
74
0
    RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
75
0
    DataSourceSurface::MappedSurface map;
76
0
    if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
77
0
        return nullptr;
78
0
79
0
    uint8_t* srcData = map.mData;
80
0
    int32_t srcStride = map.mStride;
81
0
82
0
    SurfaceFormat format = dataSurface->GetFormat();
83
0
84
0
    for (int32_t row = 0; row < aHeight; ++row) {
85
0
        for (int32_t col = 0; col < aWidth; ++col) {
86
0
            guchar* destPixel = destPixels + row * destStride + 4 * col;
87
0
88
0
            uint32_t* srcPixel =
89
0
                reinterpret_cast<uint32_t*>((srcData + row * srcStride + 4 * col));
90
0
91
0
            if (format == SurfaceFormat::B8G8R8A8) {
92
0
                const uint8_t a = (*srcPixel >> 24) & 0xFF;
93
0
                const uint8_t r = unpremultiply((*srcPixel >> 16) & 0xFF, a);
94
0
                const uint8_t g = unpremultiply((*srcPixel >>  8) & 0xFF, a);
95
0
                const uint8_t b = unpremultiply((*srcPixel >>  0) & 0xFF, a);
96
0
97
0
                *destPixel++ = r;
98
0
                *destPixel++ = g;
99
0
                *destPixel++ = b;
100
0
                *destPixel++ = a;
101
0
            } else {
102
0
                MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8);
103
0
104
0
                const uint8_t r = (*srcPixel >> 16) & 0xFF;
105
0
                const uint8_t g = (*srcPixel >>  8) & 0xFF;
106
0
                const uint8_t b = (*srcPixel >>  0) & 0xFF;
107
0
108
0
                *destPixel++ = r;
109
0
                *destPixel++ = g;
110
0
                *destPixel++ = b;
111
0
                *destPixel++ = 0xFF; // A
112
0
            }
113
0
        }
114
0
    }
115
0
116
0
    dataSurface->Unmap();
117
0
118
0
    return pixbuf;
119
0
}
120