summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/chromium/TransparencyWin.h
blob: b6bef91104cab585efd8dd4e10ce0171e9966484 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef TransparencyWin_h
#define TransparencyWin_h

#include <windows.h>

#include "AffineTransform.h"
#include "ImageBuffer.h"
#include "Noncopyable.h"
#include "wtf/OwnPtr.h"

class SkBitmap;
class SkCanvas;

namespace WebCore {

class GraphicsContext;
class TransparencyWin_NoLayer_Test;
class TransparencyWin_WhiteLayer_Test;
class TransparencyWin_TextComposite_Test;
class TransparencyWin_OpaqueCompositeLayer_Test;

// Helper class that abstracts away drawing ClearType text and Windows form
// controls either to the original context directly, or to an offscreen context
// that is composited later manually. This is to get around Windows' inability
// to handle the alpha channel, semitransparent text, and transformed form
// controls.
class TransparencyWin : public Noncopyable {
public:
    enum LayerMode {
        // No extra layer is created. Drawing will happen to the source.
        // Valid only with KeepTransform and ScaleTransform. The region being
        // drawn onto must be opaque, since the modified region will be forced
        // to opaque when drawing is complete.
        NoLayer,

        // Makes a temporary layer consisting of the composited layers below
        // it. This result must be opaque. When complete, the result will be
        // compared to the original, and the difference will be added to a thee
        // destination layer.
        //
        // This mode only works if the lower layers are opque (normally the
        // case for a web page) and layers are only drawn in the stack order,
        // meaning you can never draw underneath a layer.
        //
        // This doesn't technically produce the correct answer in all cases. If
        // you have an opaque base, a transparency layer, than a semitransparent
        // drawing on top, the result will actually be blended in twice. But
        // this isn't a very important case. This mode is used for form
        // controls which are always opaque except for occationally some
        // antialiasing. It means form control antialiasing will be too light in
        // some cases, but only if you have extra layers.
        OpaqueCompositeLayer,

        // Allows semitransparent text to be drawn on any background (even if it
        // is itself semitransparent), but disables ClearType.
        //
        // It makes a trmporary layer filled with white. This is composited with
        // the lower layer with a custom color applied to produce the result.
        // The caller must draw the text in black, and set the desired final
        // text color by calling setTextCompositeColor().
        //
        // Only valid with KeepTransform, which is the only mode where drawing
        // text in this fashion makes sense.
        TextComposite,

        // Makes a temporary layer filled with white. When complete, the layer
        // will be forced to be opqaue (since Windows may have messed up the
        // alpha channel) and composited down. Any areas not drawn into will
        // remain white.
        //
        // This is the mode of last resort. If the opacity of the final image
        // is unknown and we can't do the text trick (since we know its color),
        // then we have to live with potential white halos. This is used for
        // form control drawing, for example.
        WhiteLayer,
    };

    enum TransformMode {
        // There are no changes to the transform. Use this when drawing
        // horizontal text. The current transform must not have rotation.
        KeepTransform,

        // Drawing happens in an Untransformed space, and then that bitmap is
        // transformed according to the current context when it is copied down.
        // Requires that a layer be created (layer mode is not NoLayer).
        Untransform,

        // When the current transform only has a scaling factor applied and
        // you're drawing form elements, use this parameter. This will unscale
        // the coordinate space, so the OS will just draw the form controls
        // larger or smaller depending on the destination size.
        ScaleTransform,
    };

    // You MUST call init() below.
    // |region| is expressed relative to the current transformation.
    TransparencyWin();
    ~TransparencyWin();

    // Initializes the members if you use the 0-argument constructor. Don't call
    // this if you use the multiple-argument constructor.
    void init(GraphicsContext* dest,
              LayerMode layerMode,
              TransformMode transformMode,
              const IntRect& region);

    // Combines the source and destination bitmaps using the given mode.
    // Calling this function before the destructor runs is mandatory in most
    // cases, and harmless otherwise.  The mandatory cases are:
    //       (m_layerMode != NoLayer) || (m_transformMode == ScaleTransform)
    void composite();

    // Returns the context for drawing into, which may be the destination
    // context, or a temporary one.
    GraphicsContext* context() const { return m_drawContext; }

    PlatformGraphicsContext* platformContext() const { return m_drawContext ? m_drawContext->platformContext() : 0; }

    // When the mode is TextComposite, this sets the color that the text will
    // get. See the enum above for more.
    void setTextCompositeColor(Color color);

    // Returns the input bounds translated into the destination space. This is
    // not necessary for KeepTransform since the rectangle will be unchanged.
    const IntRect& drawRect() { return m_drawRect; }

private:
    friend TransparencyWin_NoLayer_Test;
    friend TransparencyWin_WhiteLayer_Test;
    friend TransparencyWin_TextComposite_Test;
    friend TransparencyWin_OpaqueCompositeLayer_Test;

    class OwnedBuffers;

    void computeLayerSize();

    // Sets up a new layer, if any. setupLayer() will call the appopriate layer-
    // specific helper. Must be called after computeLayerSize();
    void setupLayer();
    void setupLayerForNoLayer();
    void setupLayerForOpaqueCompositeLayer();
    void setupLayerForTextComposite();
    void setupLayerForWhiteLayer();

    // Sets up the transformation on the newly created layer. setupTransform()
    // will call the appropriate transform-specific helper. Must be called after
    // setupLayer().
    void setupTransform(const IntRect& region);
    void setupTransformForKeepTransform(const IntRect& region);
    void setupTransformForUntransform();
    void setupTransformForScaleTransform();

    void initializeNewContext();

    void compositeOpaqueComposite();
    void compositeTextComposite();

    // Fixes the alpha channel to make the region inside m_transformedRect
    // opaque.
    void makeLayerOpaque();

    // The context our drawing will eventually end up in.
    GraphicsContext* m_destContext;

    // The original transform from the destination context.
    AffineTransform m_orgTransform;

    LayerMode m_layerMode;
    TransformMode m_transformMode;

    // The rectangle we're drawing in the destination's coordinate space
    IntRect m_sourceRect;

    // The source rectangle transformed into pixels in the final image. For
    // Untransform this has no meaning, since the destination might not be a
    // rectangle.
    IntRect m_transformedSourceRect;

    // The size of the layer we created. If there's no layer, this is the size
    // of the region we're using in the source.
    IntSize m_layerSize;

    // The rectangle we're drawing to in the draw context's coordinate space.
    // This will be the same as the source rectangle except for ScaleTransform
    // where we create a new virtual coordinate space for the layer.
    IntRect m_drawRect;

    // Points to the graphics context to draw text to, which will either be
    // the original context or the copy, depending on our mode.
    GraphicsContext* m_drawContext;

    // This flag is set when we call save() on the draw context during
    // initialization. It allows us to avoid doing an extra save()/restore()
    // when one is unnecessary.
    bool m_savedOnDrawContext;

    // Used only when m_mode = TextComposite, this is the color that the text
    // will end up being once we figure out the transparency.
    Color m_textCompositeColor;

    // Layer we're drawing to.
    ImageBuffer* m_layerBuffer;

    // When the layer type is OpaqueCompositeLayer, this will contain a copy
    // of the original contents of the m_layerBuffer before Windows drew on it.
    // It allows us to re-create what Windows did to the layer. It is an
    // SkBitmap instead of an ImageBuffer because an SkBitmap is lighter-weight
    // (ImageBuffers are also GDI surfaces, which we don't need here).
    SkBitmap* m_referenceBitmap;

    // If the given size of bitmap can be cached, they will be stored here. Both
    // the bitmap and the reference are guaranteed to be allocated if this
    // member is non-null.
    static OwnedBuffers* m_cachedBuffers;

    // If a buffer was too big to be cached, it will be created temporarily, and
    // this member tracks its scope to make sure it gets deleted. Always use
    // m_layerBuffer, which will either point to this object, or the statically
    // cached one. Don't access directly.
    OwnPtr<OwnedBuffers> m_ownedBuffers;

    // Sometimes we're asked to create layers that have negative dimensions.
    // This API is not designed to fail to initialize, so we hide the fact 
    // that they are illegal and can't be rendered (failing silently, drawing
    // nothing).
    bool m_validLayer;
};

} // namespace WebCore

#endif // TransaprencyWin_h