~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2007-2009 Torch Mobile Inc.
 
3
 *  Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
 
4
 *
 
5
 *  This library is free software; you can redistribute it and/or
 
6
 *  modify it under the terms of the GNU Library General Public
 
7
 *  License as published by the Free Software Foundation; either
 
8
 *  version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 *  This library is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 *  Library General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU Library General Public License
 
16
 *  along with this library; see the file COPYING.LIB.  If not, write to
 
17
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
18
 *  Boston, MA 02110-1301, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
#include "GraphicsContext.h"
 
24
 
 
25
#include "AffineTransform.h"
 
26
#include "Font.h"
 
27
#include "GDIExtras.h"
 
28
#include "GlyphBuffer.h"
 
29
#include "Gradient.h"
 
30
#include "NotImplemented.h"
 
31
#include "Path.h"
 
32
#include "PlatformPathWinCE.h"
 
33
#include "SharedBitmap.h"
 
34
#include "SimpleFontData.h"
 
35
#include <windows.h>
 
36
#include <wtf/OwnPtr.h>
 
37
#include <wtf/unicode/CharacterNames.h>
 
38
 
 
39
namespace WebCore {
 
40
 
 
41
typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops);
 
42
typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops);
 
43
FuncGradientFillRectLinear g_linearGradientFiller = 0;
 
44
FuncGradientFillRectRadial g_radialGradientFiller = 0;
 
45
 
 
46
static inline bool isZero(double d)
 
47
{
 
48
    return d > 0 ? d <= 1.E-10 : d >= -1.E-10;
 
49
}
 
50
 
 
51
// stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1.
 
52
static inline int stableRound(double d)
 
53
{
 
54
    if (d > 0)
 
55
        return static_cast<int>(d + 0.5);
 
56
 
 
57
    int i = static_cast<int>(d);
 
58
    return i - d > 0.5 ? i - 1 : i;
 
59
}
 
60
 
 
61
// Unlike enclosingIntRect(), this function does strict rounding.
 
62
static inline IntRect roundRect(const FloatRect& r)
 
63
{
 
64
    return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.maxX()) - stableRound(r.x()), stableRound(r.maxY()) - stableRound(r.y()));
 
65
}
 
66
 
 
67
// Rotation transformation
 
68
class RotationTransform {
 
69
public:
 
70
    RotationTransform()
 
71
        : m_cosA(1.)
 
72
        , m_sinA(0.)
 
73
        , m_preShiftX(0)
 
74
        , m_preShiftY(0)
 
75
        , m_postShiftX(0)
 
76
        , m_postShiftY(0)
 
77
    {
 
78
    }
 
79
    RotationTransform operator-() const
 
80
    {
 
81
        RotationTransform rtn;
 
82
        rtn.m_cosA = m_cosA;
 
83
        rtn.m_sinA = -m_sinA;
 
84
        rtn.m_preShiftX = m_postShiftX;
 
85
        rtn.m_preShiftY = m_postShiftY;
 
86
        rtn.m_postShiftX = m_preShiftX;
 
87
        rtn.m_postShiftY = m_preShiftY;
 
88
        return rtn;
 
89
    }
 
90
    void map(double x1, double y1, double* x2, double* y2) const
 
91
    {
 
92
        x1 += m_preShiftX;
 
93
        y1 += m_preShiftY;
 
94
        *x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX;
 
95
        *y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY;
 
96
    }
 
97
    void map(int x1, int y1, int* x2, int* y2) const
 
98
    {
 
99
        x1 += m_preShiftX;
 
100
        y1 += m_preShiftY;
 
101
        *x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX;
 
102
        *y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY;
 
103
    }
 
104
 
 
105
    double m_cosA;
 
106
    double m_sinA;
 
107
    int m_preShiftX;
 
108
    int m_preShiftY;
 
109
    int m_postShiftX;
 
110
    int m_postShiftY;
 
111
};
 
112
 
 
113
template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t)
 
114
{
 
115
    int x, y;
 
116
    t.map(p.x(), p.y(), &x, &y);
 
117
    return IntPoint(x, y);
 
118
}
 
119
 
 
120
template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t)
 
121
{
 
122
    double x, y;
 
123
    t.map(p.x(), p.y(), &x, &y);
 
124
    return FloatPoint(static_cast<float>(x), static_cast<float>(y));
 
125
}
 
126
 
 
127
template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform)
 
128
{
 
129
    Value x[4], y[4];
 
130
    Value l, t, r, b;
 
131
    r = rect.maxX() - 1;
 
132
    b = rect.maxY() - 1;
 
133
    transform.map(rect.x(), rect.y(), x, y);
 
134
    transform.map(rect.x(), b, x + 1, y + 1);
 
135
    transform.map(r, b, x + 2, y + 2);
 
136
    transform.map(r, rect.y(), x + 3, y + 3);
 
137
    l = r = x[3];
 
138
    t = b = y[3];
 
139
    for (int i = 0; i < 3; ++i) {
 
140
        if (x[i] < l)
 
141
            l = x[i];
 
142
        else if (x[i] > r)
 
143
            r = x[i];
 
144
 
 
145
        if (y[i] < t)
 
146
            t = y[i];
 
147
        else if (y[i] > b)
 
148
            b = y[i];
 
149
    }
 
150
 
 
151
    return IntRect(l, t, r - l + 1, b - t + 1);
 
152
}
 
153
 
 
154
template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform)
 
155
{
 
156
    return mapRect<T, IntRect, int>(rect, transform);
 
157
}
 
158
 
 
159
template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform)
 
160
{
 
161
    return mapRect<T, FloatRect, double>(rect, transform);
 
162
}
 
163
 
 
164
class GraphicsContextPlatformPrivateData {
 
165
public:
 
166
    GraphicsContextPlatformPrivateData()
 
167
        : m_transform()
 
168
        , m_opacity(1.0)
 
169
    {
 
170
    }
 
171
 
 
172
    AffineTransform m_transform;
 
173
    float m_opacity;
 
174
};
 
175
 
 
176
enum AlphaPaintType {
 
177
    AlphaPaintNone,
 
178
    AlphaPaintImage,
 
179
    AlphaPaintOther,
 
180
};
 
181
 
 
182
class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData {
 
183
public:
 
184
    GraphicsContextPlatformPrivate(HDC dc)
 
185
        : m_dc(dc)
 
186
    {
 
187
    }
 
188
    ~GraphicsContextPlatformPrivate()
 
189
    {
 
190
        while (!m_backupData.isEmpty())
 
191
            restore();
 
192
    }
 
193
 
 
194
    void translate(float x, float y)
 
195
    {
 
196
        m_transform.translate(x, y);
 
197
    }
 
198
 
 
199
    void scale(const FloatSize& size)
 
200
    {
 
201
        m_transform.scaleNonUniform(size.width(), size.height());
 
202
    }
 
203
 
 
204
    void rotate(float radians)
 
205
    {
 
206
        m_transform.rotate(rad2deg(radians));
 
207
    }
 
208
 
 
209
    void concatCTM(const AffineTransform& transform)
 
210
    {
 
211
        m_transform *= transform;
 
212
    }
 
213
 
 
214
    void setCTM(const AffineTransform& transform)
 
215
    {
 
216
        m_transform = transform;
 
217
    }
 
218
 
 
219
    IntRect mapRect(const IntRect& rect) const
 
220
    {
 
221
        return m_transform.mapRect(rect);
 
222
    }
 
223
 
 
224
    FloatRect mapRect(const FloatRect& rect) const
 
225
    {
 
226
        return m_transform.mapRect(rect);
 
227
    }
 
228
 
 
229
    IntPoint mapPoint(const IntPoint& point) const
 
230
    {
 
231
        return m_transform.mapPoint(point);
 
232
    }
 
233
 
 
234
    FloatPoint mapPoint(const FloatPoint& point) const
 
235
    {
 
236
        return m_transform.mapPoint(point);
 
237
    }
 
238
 
 
239
    FloatSize mapSize(const FloatSize& size) const
 
240
    {
 
241
        double w, h;
 
242
        m_transform.map(size.width(), size.height(), w, h);
 
243
        return FloatSize(static_cast<float>(w), static_cast<float>(h));
 
244
    }
 
245
 
 
246
    void save()
 
247
    {
 
248
        if (m_dc)
 
249
            SaveDC(m_dc);
 
250
 
 
251
        m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this));
 
252
    }
 
253
 
 
254
    void restore()
 
255
    {
 
256
        if (m_backupData.isEmpty())
 
257
            return;
 
258
 
 
259
        if (m_dc)
 
260
            RestoreDC(m_dc, -1);
 
261
 
 
262
        GraphicsContextPlatformPrivateData::operator=(m_backupData.last());
 
263
        m_backupData.removeLast();
 
264
    }
 
265
 
 
266
    bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); }
 
267
 
 
268
    PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const
 
269
    {
 
270
        if (m_opacity <= 0)
 
271
            return 0;
 
272
 
 
273
        if (force || m_opacity < 1.)  {
 
274
            if (checkClipBox) {
 
275
                RECT clipBox;
 
276
                int clipType = GetClipBox(m_dc, &clipBox);
 
277
                if (clipType == SIMPLEREGION || clipType == COMPLEXREGION)
 
278
                    origRect.intersect(clipBox);
 
279
                if (origRect.isEmpty())
 
280
                    return 0;
 
281
            }
 
282
 
 
283
            RefPtr<SharedBitmap> bmp = SharedBitmap::create(origRect.size(), alphaPaint == AlphaPaintNone ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, false);
 
284
            SetRect(&bmpRect, 0, 0, origRect.width(), origRect.height());
 
285
            if (bmp) {
 
286
                switch (alphaPaint) {
 
287
                case AlphaPaintNone:
 
288
                case AlphaPaintImage:
 
289
                    {
 
290
                        SharedBitmap::DCHolder dc(bmp.get());
 
291
                        if (dc.get()) {
 
292
                            BitBlt(dc.get(), 0, 0, origRect.width(), origRect.height(), m_dc, origRect.x(), origRect.y(), SRCCOPY);
 
293
                            if (bmp->is32bit() && (!m_bitmap || m_bitmap->is16bit())) {
 
294
                                // Set alpha channel
 
295
                                unsigned* pixels = (unsigned*)bmp->bytes();
 
296
                                const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
 
297
                                while (pixels < pixelsEnd) {
 
298
                                    *pixels |= 0xFF000000;
 
299
                                    ++pixels;
 
300
                                }
 
301
                            }
 
302
                            return bmp;
 
303
                        }
 
304
                    }
 
305
                    break;
 
306
                //case AlphaPaintOther:
 
307
                default:
 
308
                    memset(bmp->bytes(), 0xFF, bmp->bitmapInfo().numPixels() * 4);
 
309
                    return bmp;
 
310
                    break;
 
311
                }
 
312
            }
 
313
        }
 
314
 
 
315
        bmpRect = origRect;
 
316
        return 0;
 
317
    }
 
318
 
 
319
    void paintBackTransparentLayerBitmap(HDC hdc, SharedBitmap* bmp, const IntRect& origRect, AlphaPaintType alphaPaint, const RECT& bmpRect)
 
320
    {
 
321
        if (hdc == m_dc)
 
322
            return;
 
323
 
 
324
        if (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) {
 
325
            ASSERT(bmp && bmp->bytes() && bmp->is32bit());
 
326
            unsigned* pixels = (unsigned*)bmp->bytes();
 
327
            const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
 
328
            while (pixels < pixelsEnd) {
 
329
                *pixels ^= 0xFF000000;
 
330
                ++pixels;
 
331
            }
 
332
        }
 
333
        if ((m_opacity < 1. || alphaPaint == AlphaPaintOther) && hasAlphaBlendSupport()) {
 
334
            const BLENDFUNCTION blend = { AC_SRC_OVER, 0
 
335
                , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255)
 
336
                , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA };
 
337
            bool success = alphaBlendIfSupported(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend);
 
338
            ASSERT_UNUSED(success, success);
 
339
        } else
 
340
            StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY);
 
341
    }
 
342
 
 
343
    HDC m_dc;
 
344
    RefPtr<SharedBitmap> m_bitmap;
 
345
    Vector<GraphicsContextPlatformPrivateData> m_backupData;
 
346
};
 
347
 
 
348
static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style)
 
349
{
 
350
    int width = stableRound(fWidth);
 
351
    if (width < 1)
 
352
        width = 1;
 
353
 
 
354
    int penStyle = PS_NULL;
 
355
    switch (style) {
 
356
        case SolidStroke:
 
357
#if ENABLE(CSS3_TEXT)
 
358
        case DoubleStroke:
 
359
        case WavyStroke: // FIXME: https://bugs.webkit.org/show_bug.cgi?id=94114 - Needs platform support.
 
360
#endif // CSS3_TEXT
 
361
            penStyle = PS_SOLID;
 
362
            break;
 
363
        case DottedStroke:  // not supported on Windows CE
 
364
        case DashedStroke:
 
365
            penStyle = PS_DASH;
 
366
            width = 1;
 
367
            break;
 
368
        default:
 
369
            break;
 
370
    }
 
371
 
 
372
    return adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())));
 
373
}
 
374
 
 
375
static inline PassOwnPtr<HBRUSH> createBrush(const Color& col)
 
376
{
 
377
    return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue())));
 
378
}
 
379
 
 
380
template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
 
381
{
 
382
    int destW = destBmp->width();
 
383
    int destH = destBmp->height();
 
384
    int sourceW = sourceBmp->width();
 
385
    int sourceH = sourceBmp->height();
 
386
    PixelType* dest = (PixelType*)destBmp->bytes();
 
387
    const PixelType* source = (const PixelType*)sourceBmp->bytes();
 
388
    int padding;
 
389
    int paddedSourceW;
 
390
    if (Is16bit) {
 
391
        padding = destW & 1;
 
392
        paddedSourceW = sourceW + (sourceW & 1);
 
393
    } else {
 
394
        padding = 0;
 
395
        paddedSourceW = sourceW;
 
396
    }
 
397
    if (isZero(transform.m_sinA)) {
 
398
        int cosA = transform.m_cosA > 0 ? 1 : -1;
 
399
        for (int y = 0; y < destH; ++y) {
 
400
            for (int x = 0; x < destW; ++x) {
 
401
                int x1 = x + transform.m_preShiftX;
 
402
                int y1 = y + transform.m_preShiftY;
 
403
                int srcX = x1 * cosA + transform.m_postShiftX;
 
404
                int srcY = y1 * cosA - transform.m_postShiftY;
 
405
                if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
 
406
                    *dest++ = source[srcY * paddedSourceW + srcX] | 0xFF000000;
 
407
                else
 
408
                    *dest++ |= 0xFF;
 
409
            }
 
410
            dest += padding;
 
411
        }
 
412
    } else if (isZero(transform.m_cosA)) {
 
413
        int sinA = transform.m_sinA > 0 ? 1 : -1;
 
414
        for (int y = 0; y < destH; ++y) {
 
415
            for (int x = 0; x < destW; ++x) {
 
416
                int x1 = x + transform.m_preShiftX;
 
417
                int y1 = y + transform.m_preShiftY;
 
418
                int srcX = y1 * sinA + transform.m_postShiftX;
 
419
                int srcY = -x1 * sinA + transform.m_postShiftY;
 
420
                if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
 
421
                    *dest++ = source[srcY * paddedSourceW + srcX];
 
422
            }
 
423
            dest += padding;
 
424
        }
 
425
    } else {
 
426
        for (int y = 0; y < destH; ++y) {
 
427
            for (int x = 0; x < destW; ++x) {
 
428
                // FIXME: for best quality, we should get weighted sum of four neighbours,
 
429
                // but that will be too expensive
 
430
                int srcX, srcY;
 
431
                transform.map(x, y, &srcX, &srcY);
 
432
                if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
 
433
                    *dest++ = source[srcY * paddedSourceW + srcX];
 
434
            }
 
435
            dest += padding;
 
436
        }
 
437
    }
 
438
}
 
439
 
 
440
static void rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
 
441
{
 
442
    ASSERT(destBmp->is16bit() == sourceBmp->is16bit());
 
443
    if (destBmp->is16bit())
 
444
        _rotateBitmap<unsigned short, true>(destBmp, sourceBmp, transform);
 
445
    else
 
446
        _rotateBitmap<unsigned, false>(destBmp, sourceBmp, transform);
 
447
}
 
448
 
 
449
class TransparentLayerDC {
 
450
    WTF_MAKE_NONCOPYABLE(TransparentLayerDC);
 
451
public:
 
452
    TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform = 0, int alpha = 255, bool paintImage = false);
 
453
    ~TransparentLayerDC();
 
454
 
 
455
    HDC hdc() const { return m_memDc; }
 
456
    const RECT& rect() const { return m_bmpRect; }
 
457
    IntSize toShift() const { return IntSize(m_bmpRect.left - m_origRect.x(), m_bmpRect.top - m_origRect.y()); }
 
458
    void fillAlphaChannel();
 
459
 
 
460
private:
 
461
    GraphicsContextPlatformPrivate* m_data;
 
462
    IntRect m_origRect;
 
463
    IntRect m_rotatedOrigRect;
 
464
    HDC m_memDc;
 
465
    RefPtr<SharedBitmap> m_bitmap;
 
466
    RefPtr<SharedBitmap> m_rotatedBitmap;
 
467
    RECT m_bmpRect;
 
468
    unsigned m_key;
 
469
    RotationTransform m_rotation;
 
470
    float m_oldOpacity;
 
471
    AlphaPaintType m_alphaPaintType;
 
472
};
 
473
 
 
474
TransparentLayerDC::TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform, int alpha, bool paintImage)
 
475
: m_data(data)
 
476
, m_origRect(origRect)
 
477
, m_oldOpacity(data->m_opacity)
 
478
// m_key1 and m_key2 are not initalized here. They are used only in the case that
 
479
// SharedBitmap::getDC() is called, I.E., when m_bitmap is not null.
 
480
{
 
481
    m_data->m_opacity *= alpha / 255.;
 
482
    bool mustCreateLayer;
 
483
    if (!m_data->hasAlpha()) {
 
484
        mustCreateLayer = false;
 
485
        m_alphaPaintType = AlphaPaintNone;
 
486
    } else {
 
487
        mustCreateLayer = true;
 
488
        m_alphaPaintType = paintImage ? AlphaPaintImage : AlphaPaintOther;
 
489
    }
 
490
    if (rectBeforeTransform && !isZero(m_data->m_transform.b())) {
 
491
        m_rotatedOrigRect = origRect;
 
492
        m_rotatedBitmap = m_data->getTransparentLayerBitmap(m_rotatedOrigRect, m_alphaPaintType, m_bmpRect, false, true);
 
493
        if (m_rotatedBitmap) {
 
494
            double a = m_data->m_transform.a();
 
495
            double b = m_data->m_transform.b();
 
496
            double c = _hypot(a, b);
 
497
            m_rotation.m_cosA = a / c;
 
498
            m_rotation.m_sinA = b / c;
 
499
 
 
500
            int centerX = origRect.x() + origRect.width() / 2;
 
501
            int centerY = origRect.y() + origRect.height() / 2;
 
502
            m_rotation.m_preShiftX = -centerX;
 
503
            m_rotation.m_preShiftY = -centerY;
 
504
            m_rotation.m_postShiftX = centerX;
 
505
            m_rotation.m_postShiftY = centerY;
 
506
 
 
507
            m_origRect = mapRect(m_rotatedOrigRect, m_rotation);
 
508
 
 
509
            m_rotation.m_preShiftX += m_rotatedOrigRect.x();
 
510
            m_rotation.m_preShiftY += m_rotatedOrigRect.y();
 
511
            m_rotation.m_postShiftX -= m_origRect.x();
 
512
            m_rotation.m_postShiftY -= m_origRect.y();
 
513
 
 
514
            FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->location()));
 
515
            FloatPoint topRight(rectBeforeTransform->maxX() - 1, rectBeforeTransform->y());
 
516
            topRight = m_data->m_transform.mapPoint(topRight);
 
517
            FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->maxY() - 1);
 
518
            bottomLeft = m_data->m_transform.mapPoint(bottomLeft);
 
519
            FloatSize sideTop = topRight - topLeft;
 
520
            FloatSize sideLeft = bottomLeft - topLeft;
 
521
            float width = _hypot(sideTop.width() + 1, sideTop.height() + 1);
 
522
            float height = _hypot(sideLeft.width() + 1, sideLeft.height() + 1);
 
523
 
 
524
            origRect.inflateX(stableRound((width - origRect.width()) * 0.5));
 
525
            origRect.inflateY(stableRound((height - origRect.height()) * 0.5));
 
526
 
 
527
            m_bitmap = SharedBitmap::create(m_origRect.size(), m_rotatedBitmap->is16bit() ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, true);
 
528
            if (m_bitmap)
 
529
                rotateBitmap(m_bitmap.get(), m_rotatedBitmap.get(), -m_rotation);
 
530
            else
 
531
                m_rotatedBitmap = 0;
 
532
        }
 
533
    } else
 
534
        m_bitmap = m_data->getTransparentLayerBitmap(m_origRect, m_alphaPaintType, m_bmpRect, true, mustCreateLayer);
 
535
    if (m_bitmap)
 
536
        m_memDc = m_bitmap->getDC(&m_key);
 
537
    else
 
538
        m_memDc = m_data->m_dc;
 
539
}
 
540
 
 
541
TransparentLayerDC::~TransparentLayerDC()
 
542
{
 
543
    if (m_rotatedBitmap) {
 
544
        m_bitmap->releaseDC(m_memDc, m_key);
 
545
        m_key = 0;
 
546
        rotateBitmap(m_rotatedBitmap.get(), m_bitmap.get(), m_rotation);
 
547
        m_memDc = m_rotatedBitmap->getDC(&m_key);
 
548
        m_data->paintBackTransparentLayerBitmap(m_memDc, m_rotatedBitmap.get(), m_rotatedOrigRect, m_alphaPaintType, m_bmpRect);
 
549
        m_rotatedBitmap->releaseDC(m_memDc, m_key);
 
550
    } else if (m_bitmap) {
 
551
        m_data->paintBackTransparentLayerBitmap(m_memDc, m_bitmap.get(), m_origRect, m_alphaPaintType, m_bmpRect);
 
552
        m_bitmap->releaseDC(m_memDc, m_key);
 
553
    }
 
554
    m_data->m_opacity = m_oldOpacity;
 
555
}
 
556
 
 
557
void TransparentLayerDC::fillAlphaChannel()
 
558
{
 
559
    if (!m_bitmap || !m_bitmap->is32bit())
 
560
        return;
 
561
 
 
562
    unsigned* pixels = (unsigned*)m_bitmap->bytes();
 
563
    const unsigned* const pixelsEnd = pixels + m_bitmap->bitmapInfo().numPixels();
 
564
    while (pixels < pixelsEnd) {
 
565
        *pixels |= 0xFF000000;
 
566
        ++pixels;
 
567
    }
 
568
}
 
569
 
 
570
class ScopeDCProvider {
 
571
    WTF_MAKE_NONCOPYABLE(ScopeDCProvider);
 
572
public:
 
573
    explicit ScopeDCProvider(GraphicsContextPlatformPrivate* data)
 
574
        : m_data(data)
 
575
    {
 
576
        if (m_data->m_bitmap)
 
577
            m_data->m_dc = m_data->m_bitmap->getDC(&m_key);
 
578
    }
 
579
    ~ScopeDCProvider()
 
580
    {
 
581
        if (m_data->m_bitmap) {
 
582
            m_data->m_bitmap->releaseDC(m_data->m_dc, m_key);
 
583
            m_data->m_dc = 0;
 
584
        }
 
585
    }
 
586
private:
 
587
    GraphicsContextPlatformPrivate* m_data;
 
588
    unsigned m_key;
 
589
};
 
590
 
 
591
 
 
592
void GraphicsContext::platformInit(PlatformGraphicsContext* dc)
 
593
{
 
594
    m_data = new GraphicsContextPlatformPrivate(dc);
 
595
}
 
596
 
 
597
void GraphicsContext::platformDestroy()
 
598
{
 
599
    delete m_data;
 
600
}
 
601
 
 
602
void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp)
 
603
{
 
604
    ASSERT(!m_data->m_dc);
 
605
    m_data->m_bitmap = bmp;
 
606
}
 
607
 
 
608
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
 
609
{
 
610
    // FIXME: Add support for AlphaBlend.
 
611
    ASSERT(!supportAlphaBlend);
 
612
    return m_data->m_dc;
 
613
}
 
614
 
 
615
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
 
616
{
 
617
}
 
618
 
 
619
void GraphicsContext::savePlatformState()
 
620
{
 
621
    m_data->save();
 
622
}
 
623
 
 
624
void GraphicsContext::restorePlatformState()
 
625
{
 
626
    m_data->restore();
 
627
}
 
628
 
 
629
void GraphicsContext::drawRect(const IntRect& rect)
 
630
{
 
631
    if (!m_data->m_opacity || paintingDisabled() || rect.isEmpty())
 
632
        return;
 
633
 
 
634
    ScopeDCProvider dcProvider(m_data);
 
635
    if (!m_data->m_dc)
 
636
        return;
 
637
 
 
638
    IntRect trRect = m_data->mapRect(rect);
 
639
    TransparentLayerDC transparentDC(m_data, trRect, &rect);
 
640
    HDC dc = transparentDC.hdc();
 
641
    if (!dc)
 
642
        return;
 
643
    trRect.move(transparentDC.toShift());
 
644
 
 
645
    OwnPtr<HBRUSH> brush;
 
646
    HGDIOBJ oldBrush;
 
647
    if (fillColor().alpha()) {
 
648
        brush = createBrush(fillColor());
 
649
        oldBrush = SelectObject(dc, brush.get());
 
650
    } else
 
651
        oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
 
652
 
 
653
    OwnPtr<HPEN> pen;
 
654
    HGDIOBJ oldPen;
 
655
    if (strokeStyle() != NoStroke) {
 
656
        pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
657
        oldPen = SelectObject(dc, pen.get());
 
658
    } else
 
659
        oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
 
660
 
 
661
    if (brush || pen) {
 
662
        if (trRect.width() <= 0)
 
663
            trRect.setWidth(1);
 
664
        if (trRect.height() <= 0)
 
665
            trRect.setHeight(1);
 
666
 
 
667
        Rectangle(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
 
668
    }
 
669
 
 
670
    SelectObject(dc, oldPen);
 
671
    SelectObject(dc, oldBrush);
 
672
}
 
673
 
 
674
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
 
675
{
 
676
    if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || !strokeColor().alpha())
 
677
        return;
 
678
 
 
679
    ScopeDCProvider dcProvider(m_data);
 
680
    if (!m_data->m_dc)
 
681
        return;
 
682
 
 
683
    IntPoint trPoint1 = m_data->mapPoint(point1);
 
684
    IntPoint trPoint2 = m_data->mapPoint(point2);
 
685
 
 
686
    IntRect lineRect(trPoint1, trPoint2 - trPoint1);
 
687
    lineRect.setHeight(lineRect.height() + strokeThickness());
 
688
    TransparentLayerDC transparentDC(m_data, lineRect, 0, strokeColor().alpha());
 
689
    HDC dc = transparentDC.hdc();
 
690
    if (!dc)
 
691
        return;
 
692
    trPoint1 += transparentDC.toShift();
 
693
    trPoint2 += transparentDC.toShift();
 
694
 
 
695
    OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
696
    HGDIOBJ oldPen = SelectObject(dc, pen.get());
 
697
 
 
698
    MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0);
 
699
    LineTo(dc, trPoint2.x(), trPoint2.y());
 
700
 
 
701
    SelectObject(dc, oldPen);
 
702
}
 
703
 
 
704
void GraphicsContext::drawEllipse(const IntRect& rect)
 
705
{
 
706
    if (!m_data->m_opacity || paintingDisabled() || (!fillColor().alpha() && strokeStyle() == NoStroke))
 
707
        return;
 
708
 
 
709
    ScopeDCProvider dcProvider(m_data);
 
710
    if (!m_data->m_dc)
 
711
        return;
 
712
 
 
713
    IntRect trRect = m_data->mapRect(rect);
 
714
    TransparentLayerDC transparentDC(m_data, trRect, &rect);
 
715
    HDC dc = transparentDC.hdc();
 
716
    if (!dc)
 
717
        return;
 
718
    trRect.move(transparentDC.toShift());
 
719
 
 
720
    OwnPtr<HBRUSH> brush;
 
721
    HGDIOBJ oldBrush;
 
722
    if (fillColor().alpha()) {
 
723
        brush = createBrush(fillColor());
 
724
        oldBrush = SelectObject(dc, brush.get());
 
725
    } else
 
726
        oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
 
727
 
 
728
    OwnPtr<HPEN> pen;
 
729
    HGDIOBJ oldPen = 0;
 
730
    if (strokeStyle() != NoStroke) {
 
731
        pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
732
        oldPen = SelectObject(dc, pen.get());
 
733
    } else
 
734
        oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
 
735
 
 
736
    if (brush || pen)
 
737
        Ellipse(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
 
738
 
 
739
    SelectObject(dc, oldPen);
 
740
    SelectObject(dc, oldBrush);
 
741
}
 
742
 
 
743
static inline bool equalAngle(double a, double b) 
 
744
{
 
745
    return fabs(a - b) < 1E-5;
 
746
}
 
747
 
 
748
void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y)
 
749
{
 
750
    while (angle < 0)
 
751
        angle += 2 * piDouble;
 
752
    while (angle >= 2 * piDouble)
 
753
        angle -= 2 * piDouble;
 
754
 
 
755
    if (equalAngle(angle, 0) || equalAngle(angle, 2 * piDouble)) {
 
756
        x = a;
 
757
        y = 0;
 
758
    } else if (equalAngle(angle, piDouble)) {
 
759
        x = -a;
 
760
        y = 0;
 
761
    } else if (equalAngle(angle, .5 * piDouble)) {
 
762
        x = 0;
 
763
        y = b;
 
764
    } else if (equalAngle(angle, 1.5 * piDouble)) {
 
765
        x = 0;
 
766
        y = -b;
 
767
    } else {
 
768
        double k = tan(angle);
 
769
        double sqA = a * a;
 
770
        double sqB = b * b;
 
771
        double tmp = 1. / (1. / sqA + (k * k) / sqB);
 
772
        tmp = tmp <= 0 ? 0 : sqrt(tmp);
 
773
        if (angle > .5 * piDouble && angle < 1.5 * piDouble)
 
774
            tmp = -tmp;
 
775
        x = tmp;
 
776
 
 
777
        k = tan(.5 * piDouble - angle);
 
778
        tmp = 1. / ((k * k) / sqA + 1 / sqB);
 
779
        tmp = tmp <= 0 ? 0 : sqrt(tmp);
 
780
        if (angle > piDouble)
 
781
            tmp = -tmp;
 
782
        y = tmp;
 
783
    }
 
784
}
 
785
 
 
786
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
 
787
{
 
788
    if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || rect.isEmpty())
 
789
        return;
 
790
 
 
791
    ScopeDCProvider dcProvider(m_data);
 
792
    if (!m_data->m_dc)
 
793
        return;
 
794
 
 
795
    IntRect trRect = m_data->mapRect(rect);
 
796
    TransparentLayerDC transparentDC(m_data, trRect, &rect);
 
797
    HDC dc = transparentDC.hdc();
 
798
    if (!dc)
 
799
        return;
 
800
    trRect.move(transparentDC.toShift());
 
801
 
 
802
    OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
803
    HGDIOBJ oldPen = SelectObject(dc, pen.get());
 
804
 
 
805
    double a = trRect.width() * 0.5;
 
806
    double b = trRect.height() * 0.5;
 
807
    int centerX = stableRound(trRect.x() + a);
 
808
    int centerY = stableRound(trRect.y() + b);
 
809
    float fstartX, fstartY, fendX, fendY;
 
810
    int startX, startY, endX, endY;
 
811
    getEllipsePointByAngle(deg2rad((double)startAngle), a, b, fstartX, fstartY);
 
812
    getEllipsePointByAngle(deg2rad((double)startAngle + angleSpan), a, b, fendX, fendY);
 
813
    startX = stableRound(fstartX);
 
814
    startY = stableRound(fstartY);
 
815
    endX = stableRound(fendX);
 
816
    endY = stableRound(fendY);
 
817
 
 
818
    startX += centerX;
 
819
    startY = centerY - startY;
 
820
    endX += centerX;
 
821
    endY = centerY - endY;
 
822
    RECT clipRect;
 
823
    if (startX < endX) {
 
824
        clipRect.left = startX;
 
825
        clipRect.right = endX;
 
826
    } else {
 
827
        clipRect.left = endX;
 
828
        clipRect.right = startX;
 
829
    }
 
830
    if (startY < endY) {
 
831
        clipRect.top = startY;
 
832
        clipRect.bottom = endY;
 
833
    } else {
 
834
        clipRect.top = endY;
 
835
        clipRect.bottom = startY;
 
836
    }
 
837
 
 
838
    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
 
839
    bool newClip;
 
840
    if (GetClipRgn(dc, clipRgn.get()) <= 0) {
 
841
        newClip = true;
 
842
        clipRgn = adoptPtr(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
 
843
        SelectClipRgn(dc, clipRgn.get());
 
844
    } else {
 
845
        newClip = false;
 
846
        IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
 
847
    }
 
848
 
 
849
    HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
 
850
    Ellipse(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
 
851
    SelectObject(dc, oldBrush);
 
852
 
 
853
    if (newClip)
 
854
        SelectClipRgn(dc, 0);
 
855
    else
 
856
        SelectClipRgn(dc, clipRgn.get());
 
857
 
 
858
    SelectObject(dc, oldPen);
 
859
}
 
860
 
 
861
void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
 
862
{
 
863
    if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points)
 
864
        return;
 
865
 
 
866
    ScopeDCProvider dcProvider(m_data);
 
867
    if (!m_data->m_dc)
 
868
        return;
 
869
 
 
870
    Vector<POINT, 20> winPoints(npoints);
 
871
    FloatPoint trPoint = m_data->mapPoint(points[0]);
 
872
    winPoints[0].x = stableRound(trPoint.x());
 
873
    winPoints[0].y = stableRound(trPoint.y());
 
874
    RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y };
 
875
    for (size_t i = 1; i < npoints; ++i) {
 
876
        trPoint = m_data->mapPoint(points[i]);
 
877
        winPoints[i].x = stableRound(trPoint.x());
 
878
        winPoints[i].y = stableRound(trPoint.y());
 
879
        if (rect.left > winPoints[i].x)
 
880
            rect.left = winPoints[i].x;
 
881
        else if (rect.right < winPoints[i].x)
 
882
            rect.right = winPoints[i].x;
 
883
        if (rect.top > winPoints[i].y)
 
884
            rect.top = winPoints[i].y;
 
885
        else if (rect.bottom < winPoints[i].y)
 
886
            rect.bottom = winPoints[i].y;
 
887
    }
 
888
    rect.bottom += 1;
 
889
    rect.right += 1;
 
890
 
 
891
    IntRect intRect(rect);
 
892
    TransparentLayerDC transparentDC(m_data, intRect);
 
893
    HDC dc = transparentDC.hdc();
 
894
    if (!dc)
 
895
        return;
 
896
 
 
897
    for (size_t i = 0; i < npoints; ++i) {
 
898
        winPoints[i].x += transparentDC.toShift().width();
 
899
        winPoints[i].y += transparentDC.toShift().height();
 
900
    }
 
901
 
 
902
    OwnPtr<HBRUSH> brush;
 
903
    HGDIOBJ oldBrush;
 
904
    if (fillColor().alpha()) {
 
905
        brush = createBrush(fillColor());
 
906
        oldBrush = SelectObject(dc, brush.get());
 
907
    } else
 
908
        oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
 
909
 
 
910
    OwnPtr<HPEN> pen;
 
911
    HGDIOBJ oldPen;
 
912
    if (strokeStyle() != NoStroke) {
 
913
        pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
914
        oldPen = SelectObject(dc, pen.get());
 
915
    } else
 
916
        oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
 
917
 
 
918
    if (brush || pen)
 
919
        Polygon(dc, winPoints.data(), npoints);
 
920
 
 
921
    SelectObject(dc, oldPen);
 
922
    SelectObject(dc, oldBrush);
 
923
}
 
924
 
 
925
void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
 
926
{
 
927
    if (paintingDisabled())
 
928
        return;
 
929
 
 
930
    if (numPoints <= 1)
 
931
        return;
 
932
    
 
933
    // FIXME: IMPLEMENT!!
 
934
}
 
935
 
 
936
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
 
937
{
 
938
    if (paintingDisabled() || !m_data->m_opacity)
 
939
        return;
 
940
 
 
941
    int alpha = color.alpha();
 
942
    if (!alpha)
 
943
        return;
 
944
 
 
945
    ScopeDCProvider dcProvider(m_data);
 
946
    if (!m_data->m_dc)
 
947
        return;
 
948
 
 
949
    IntRect intRect = enclosingIntRect(rect);
 
950
    TransparentLayerDC transparentDC(m_data, m_data->mapRect(intRect), &intRect, alpha);
 
951
 
 
952
    if (!transparentDC.hdc())
 
953
        return;
 
954
 
 
955
    OwnPtr<HBRUSH> hbrush = adoptPtr(CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
 
956
    FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get());
 
957
}
 
958
 
 
959
void GraphicsContext::clip(const FloatRect& rect)
 
960
{
 
961
    if (paintingDisabled())
 
962
        return;
 
963
 
 
964
    if (!m_data->m_dc)
 
965
        return;
 
966
 
 
967
    IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
 
968
 
 
969
    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
 
970
    if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0)
 
971
        IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
 
972
    else {
 
973
        clipRgn = adoptPtr(CreateRectRgn(trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()));
 
974
        SelectClipRgn(m_data->m_dc, clipRgn.get());
 
975
    }
 
976
}
 
977
 
 
978
void GraphicsContext::clipOut(const IntRect& rect)
 
979
{
 
980
    if (paintingDisabled())
 
981
        return;
 
982
 
 
983
    if (!m_data->m_dc)
 
984
        return;
 
985
 
 
986
    IntRect trRect = m_data->mapRect(rect);
 
987
 
 
988
    ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
 
989
}
 
990
 
 
991
void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
 
992
{
 
993
    // FIXME: implement
 
994
}
 
995
 
 
996
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
 
997
{
 
998
    if (!m_data->m_opacity || paintingDisabled())
 
999
        return;
 
1000
 
 
1001
    ScopeDCProvider dcProvider(m_data);
 
1002
    if (!m_data->m_dc)
 
1003
        return;
 
1004
 
 
1005
    int radius = (width - 1) / 2;
 
1006
    offset += radius;
 
1007
 
 
1008
    unsigned rectCount = rects.size();
 
1009
    IntRect finalFocusRect;
 
1010
    for (unsigned i = 0; i < rectCount; i++) {
 
1011
        IntRect focusRect = rects[i];
 
1012
        focusRect.inflate(offset);
 
1013
        finalFocusRect.unite(focusRect);
 
1014
    }
 
1015
 
 
1016
    IntRect intRect = finalFocusRect;
 
1017
    IntRect trRect = m_data->mapRect(finalFocusRect);
 
1018
    TransparentLayerDC transparentDC(m_data, trRect, &intRect);
 
1019
    HDC dc = transparentDC.hdc();
 
1020
    if (!dc)
 
1021
        return;
 
1022
    trRect.move(transparentDC.toShift());
 
1023
 
 
1024
    RECT rect = trRect;
 
1025
    DrawFocusRect(dc, &rect);
 
1026
}
 
1027
 
 
1028
void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing)
 
1029
{
 
1030
    if (paintingDisabled())
 
1031
        return;
 
1032
 
 
1033
    StrokeStyle oldStyle = strokeStyle();
 
1034
    setStrokeStyle(SolidStroke);
 
1035
    drawLine(roundedIntPoint(origin), roundedIntPoint(origin + FloatSize(width, 0)));
 
1036
    setStrokeStyle(oldStyle);
 
1037
}
 
1038
 
 
1039
void GraphicsContext::drawLineForDocumentMarker(const FloatPoint&, float width, DocumentMarkerLineStyle style)
 
1040
{
 
1041
    notImplemented();
 
1042
}
 
1043
 
 
1044
void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
 
1045
{
 
1046
    notImplemented();
 
1047
}
 
1048
 
 
1049
void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
 
1050
{
 
1051
    notImplemented();
 
1052
}
 
1053
 
 
1054
void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
 
1055
{
 
1056
    notImplemented();
 
1057
}
 
1058
 
 
1059
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
 
1060
{
 
1061
    notImplemented();
 
1062
}
 
1063
 
 
1064
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
 
1065
{
 
1066
    // We can only clip rectangles on WINCE
 
1067
    clip(rect);
 
1068
}
 
1069
 
 
1070
void GraphicsContext::clearRect(const FloatRect& rect)
 
1071
{
 
1072
    if (paintingDisabled())
 
1073
        return;
 
1074
 
 
1075
    if (m_data->hasAlpha()) {
 
1076
        IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
 
1077
        m_data->m_bitmap->clearPixels(trRect);
 
1078
        return;
 
1079
    } 
 
1080
 
 
1081
    fillRect(rect, Color(Color::white), ColorSpaceDeviceRGB);
 
1082
}
 
1083
 
 
1084
void GraphicsContext::strokeRect(const FloatRect& rect, float width)
 
1085
{
 
1086
    if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke)
 
1087
        return;
 
1088
 
 
1089
    ScopeDCProvider dcProvider(m_data);
 
1090
    if (!m_data->m_dc)
 
1091
        return;
 
1092
 
 
1093
    IntRect intRect = enclosingIntRect(rect);
 
1094
    IntRect trRect = m_data->mapRect(intRect);
 
1095
    TransparentLayerDC transparentDC(m_data, trRect, &intRect);
 
1096
    HDC dc = transparentDC.hdc();
 
1097
    if (!dc)
 
1098
        return;
 
1099
    trRect.move(transparentDC.toShift());
 
1100
 
 
1101
    OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
1102
    HGDIOBJ oldPen = SelectObject(dc, pen.get());
 
1103
 
 
1104
    int right = trRect.maxX() - 1;
 
1105
    int bottom = trRect.maxY() - 1;
 
1106
    const POINT intPoints[5] =
 
1107
    {
 
1108
        { trRect.x(), trRect.y() },
 
1109
        { right, trRect.y() },
 
1110
        { right, bottom },
 
1111
        { trRect.x(), bottom },
 
1112
        { trRect.x(), trRect.y() }
 
1113
    };
 
1114
 
 
1115
    Polyline(dc, intPoints, 5);
 
1116
 
 
1117
    SelectObject(dc, oldPen);
 
1118
}
 
1119
 
 
1120
void GraphicsContext::beginPlatformTransparencyLayer(float opacity)
 
1121
{
 
1122
    m_data->save();
 
1123
    m_data->m_opacity *= opacity;
 
1124
}
 
1125
 
 
1126
void GraphicsContext::endPlatformTransparencyLayer()
 
1127
{
 
1128
    m_data->restore();
 
1129
}
 
1130
 
 
1131
bool GraphicsContext::supportsTransparencyLayers()
 
1132
{
 
1133
    return true;
 
1134
}
 
1135
 
 
1136
void GraphicsContext::concatCTM(const AffineTransform& transform)
 
1137
{
 
1138
    m_data->concatCTM(transform);
 
1139
}
 
1140
 
 
1141
void GraphicsContext::setCTM(const AffineTransform& transform)
 
1142
{
 
1143
    m_data->setCTM(transform);
 
1144
}
 
1145
 
 
1146
AffineTransform& GraphicsContext::affineTransform()
 
1147
{
 
1148
    return m_data->m_transform;
 
1149
}
 
1150
 
 
1151
const AffineTransform& GraphicsContext::affineTransform() const
 
1152
{
 
1153
    return m_data->m_transform;
 
1154
}
 
1155
 
 
1156
void GraphicsContext::resetAffineTransform()
 
1157
{
 
1158
    m_data->m_transform.makeIdentity();
 
1159
}
 
1160
 
 
1161
void GraphicsContext::translate(float x, float y)
 
1162
{
 
1163
    m_data->translate(x, y);
 
1164
}
 
1165
 
 
1166
void GraphicsContext::rotate(float radians)
 
1167
{
 
1168
    m_data->rotate(radians);
 
1169
}
 
1170
 
 
1171
void GraphicsContext::scale(const FloatSize& size)
 
1172
{
 
1173
    m_data->scale(size);
 
1174
}
 
1175
 
 
1176
void GraphicsContext::setLineCap(LineCap lineCap)
 
1177
{
 
1178
    notImplemented();
 
1179
}
 
1180
 
 
1181
void GraphicsContext::setLineJoin(LineJoin lineJoin)
 
1182
{
 
1183
    notImplemented();
 
1184
}
 
1185
 
 
1186
void GraphicsContext::setMiterLimit(float miter)
 
1187
{
 
1188
    notImplemented();
 
1189
}
 
1190
 
 
1191
void GraphicsContext::setAlpha(float alpha)
 
1192
{
 
1193
    m_data->m_opacity = alpha;
 
1194
}
 
1195
 
 
1196
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
 
1197
{
 
1198
    notImplemented();
 
1199
}
 
1200
 
 
1201
void GraphicsContext::clip(const Path& path)
 
1202
{
 
1203
    notImplemented();
 
1204
}
 
1205
 
 
1206
void GraphicsContext::canvasClip(const Path& path)
 
1207
{
 
1208
    clip(path);
 
1209
}
 
1210
 
 
1211
void GraphicsContext::clipOut(const Path&)
 
1212
{
 
1213
    notImplemented();
 
1214
}
 
1215
 
 
1216
static inline IntPoint rectCenterPoint(const RECT& rect)
 
1217
{
 
1218
    return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2);
 
1219
}
 
1220
void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace)
 
1221
{
 
1222
    ScopeDCProvider dcProvider(m_data);
 
1223
    if (!m_data->m_dc)
 
1224
        return;
 
1225
 
 
1226
    FloatSize shadowOffset;
 
1227
    float shadowBlur = 0;
 
1228
    Color shadowColor;
 
1229
    ColorSpace shadowColorSpace;
 
1230
        
 
1231
    getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
 
1232
    
 
1233
    IntRect dstRect = fillRect;
 
1234
    
 
1235
    dstRect.move(stableRound(shadowOffset.width()), stableRound(shadowOffset.height()));
 
1236
    dstRect.inflate(stableRound(shadowBlur));
 
1237
    dstRect = m_data->mapRect(dstRect);
 
1238
  
 
1239
    FloatSize newTopLeft(m_data->mapSize(topLeft));
 
1240
    FloatSize newTopRight(m_data->mapSize(topRight));
 
1241
    FloatSize newBottomLeft(m_data->mapSize(bottomLeft));
 
1242
    FloatSize newBottomRight(m_data->mapSize(bottomRight));
 
1243
 
 
1244
    TransparentLayerDC transparentDc(m_data, dstRect, &fillRect);
 
1245
    HDC dc = transparentDc.hdc();
 
1246
    if (!dc)
 
1247
        return;
 
1248
 
 
1249
    dstRect.move(transparentDc.toShift());
 
1250
 
 
1251
    RECT rectWin = dstRect;
 
1252
 
 
1253
    OwnPtr<HBRUSH> brush = createBrush(shadowColor);
 
1254
    HGDIOBJ oldBrush = SelectObject(dc, brush.get());
 
1255
 
 
1256
    SelectObject(dc, GetStockObject(NULL_PEN));
 
1257
 
 
1258
    IntPoint centerPoint = rectCenterPoint(rectWin);
 
1259
    // Draw top left half
 
1260
    RECT clipRect(rectWin);
 
1261
    clipRect.right = centerPoint.x();
 
1262
    clipRect.bottom = centerPoint.y();
 
1263
 
 
1264
    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
 
1265
    bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0);
 
1266
    
 
1267
    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2));
 
1268
 
 
1269
    // Draw top right
 
1270
    clipRect = rectWin;
 
1271
    clipRect.left = centerPoint.x();
 
1272
    clipRect.bottom = centerPoint.y();
 
1273
 
 
1274
    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2));
 
1275
 
 
1276
     // Draw bottom left
 
1277
    clipRect = rectWin;
 
1278
    clipRect.right = centerPoint.x();
 
1279
    clipRect.top = centerPoint.y();
 
1280
 
 
1281
    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2));
 
1282
 
 
1283
    // Draw bottom right
 
1284
    clipRect = rectWin;
 
1285
    clipRect.left = centerPoint.x();
 
1286
    clipRect.top = centerPoint.y();
 
1287
 
 
1288
    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
 
1289
 
 
1290
    SelectObject(dc, oldBrush);
 
1291
}
 
1292
 
 
1293
 
 
1294
void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height)
 
1295
{
 
1296
    if (!dc)
 
1297
        return;
 
1298
 
 
1299
    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
 
1300
    if (needsNewClip) {
 
1301
        clipRgn = adoptPtr(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
 
1302
        SelectClipRgn(dc, clipRgn.get());
 
1303
    } else
 
1304
        IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
 
1305
 
 
1306
    ::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height);
 
1307
 
 
1308
    SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get());
 
1309
}
 
1310
 
 
1311
 
 
1312
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
 
1313
{
 
1314
    notImplemented();
 
1315
    return frect;
 
1316
}
 
1317
 
 
1318
Color gradientAverageColor(const Gradient* gradient)
 
1319
{
 
1320
    const Vector<Gradient::ColorStop>& stops = gradient->getStops();
 
1321
    if (stops.isEmpty())
 
1322
        return Color();
 
1323
 
 
1324
    const Gradient::ColorStop& stop = stops.first();
 
1325
    if (stops.size() == 1)
 
1326
        return Color(stop.red, stop.green, stop.blue, stop.alpha);
 
1327
 
 
1328
    const Gradient::ColorStop& lastStop = stops.last();
 
1329
    return Color((stop.red + lastStop.red) * 0.5f
 
1330
        , (stop.green + lastStop.green) * 0.5f
 
1331
        , (stop.blue + lastStop.blue) * 0.5f
 
1332
        , (stop.alpha + lastStop.alpha) * 0.5f);
 
1333
}
 
1334
 
 
1335
void GraphicsContext::fillPath(const Path& path)
 
1336
{
 
1337
    if (path.isNull())
 
1338
        return;
 
1339
 
 
1340
    Color c = m_state.fillGradient
 
1341
        ? gradientAverageColor(m_state.fillGradient.get())
 
1342
        : fillColor();
 
1343
 
 
1344
    if (!c.alpha() || !m_data->m_opacity)
 
1345
        return;
 
1346
 
 
1347
    ScopeDCProvider dcProvider(m_data);
 
1348
    if (!m_data->m_dc)
 
1349
        return;
 
1350
 
 
1351
    OwnPtr<HBRUSH> brush = createBrush(c);
 
1352
 
 
1353
    if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
 
1354
        IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
 
1355
        trRect.inflate(1);
 
1356
        TransparentLayerDC transparentDC(m_data, trRect);
 
1357
        HDC dc = transparentDC.hdc();
 
1358
        if (!dc)
 
1359
            return;
 
1360
 
 
1361
        AffineTransform tr = m_data->m_transform;
 
1362
        tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
 
1363
 
 
1364
        SelectObject(dc, GetStockObject(NULL_PEN));
 
1365
        HGDIOBJ oldBrush = SelectObject(dc, brush.get());
 
1366
        path.platformPath()->fillPath(dc, &tr);
 
1367
        SelectObject(dc, oldBrush);
 
1368
    } else {
 
1369
        SelectObject(m_data->m_dc, GetStockObject(NULL_PEN));
 
1370
        HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get());
 
1371
        path.platformPath()->fillPath(m_data->m_dc, &m_data->m_transform);
 
1372
        SelectObject(m_data->m_dc, oldBrush);
 
1373
    }
 
1374
}
 
1375
 
 
1376
 
 
1377
void GraphicsContext::strokePath(const Path& path)
 
1378
{
 
1379
    if (path.isNull() || !m_data->m_opacity)
 
1380
        return;
 
1381
 
 
1382
    ScopeDCProvider dcProvider(m_data);
 
1383
    if (!m_data->m_dc)
 
1384
        return;
 
1385
 
 
1386
    OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
 
1387
 
 
1388
    if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
 
1389
        IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
 
1390
        trRect.inflate(1);
 
1391
        TransparentLayerDC transparentDC(m_data, trRect);
 
1392
        HDC dc = transparentDC.hdc();
 
1393
        if (!dc)
 
1394
            return;
 
1395
 
 
1396
        AffineTransform tr = m_data->m_transform;
 
1397
        tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
 
1398
 
 
1399
        SelectObject(dc, GetStockObject(NULL_BRUSH));
 
1400
        HGDIOBJ oldPen = SelectObject(dc, pen.get());
 
1401
        path.platformPath()->strokePath(dc, &tr);
 
1402
        SelectObject(dc, oldPen);
 
1403
    } else {
 
1404
        SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH));
 
1405
        HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get());
 
1406
        path.platformPath()->strokePath(m_data->m_dc, &m_data->m_transform);
 
1407
        SelectObject(m_data->m_dc, oldPen);
 
1408
    }
 
1409
}
 
1410
 
 
1411
void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient)
 
1412
{
 
1413
    if (!m_data->m_opacity)
 
1414
        return;
 
1415
 
 
1416
    const Vector<Gradient::ColorStop>& stops = gradient->getStops();
 
1417
    if (stops.isEmpty())
 
1418
        return;
 
1419
 
 
1420
    size_t numStops = stops.size();
 
1421
    if (numStops == 1) {
 
1422
        const Gradient::ColorStop& stop = stops.first();
 
1423
        Color color(stop.red, stop.green, stop.blue, stop.alpha);
 
1424
        fillRect(r, color, ColorSpaceDeviceRGB);
 
1425
        return;
 
1426
    } 
 
1427
    
 
1428
    ScopeDCProvider dcProvider(m_data);
 
1429
    if (!m_data->m_dc)
 
1430
        return;
 
1431
 
 
1432
    IntRect intRect = enclosingIntRect(r);
 
1433
    IntRect rect = m_data->mapRect(intRect);
 
1434
    TransparentLayerDC transparentDC(m_data, rect, &intRect, 255, true);
 
1435
    HDC dc = transparentDC.hdc();
 
1436
    if (!dc)
 
1437
        return;
 
1438
 
 
1439
    rect.move(transparentDC.toShift());
 
1440
    FloatPoint fp0 = m_data->mapPoint(gradient->p0());
 
1441
    FloatPoint fp1 = m_data->mapPoint(gradient->p1());
 
1442
    IntPoint p0(stableRound(fp0.x()), stableRound(fp0.y()));
 
1443
    IntPoint p1(stableRound(fp1.x()), stableRound(fp1.y()));
 
1444
    p0 += transparentDC.toShift();
 
1445
    p1 += transparentDC.toShift();
 
1446
 
 
1447
    if (gradient->isRadial()) {
 
1448
        if (g_radialGradientFiller) {
 
1449
            // FIXME: don't support 2D scaling at this time
 
1450
            double scale = (m_data->m_transform.a() + m_data->m_transform.d()) * 0.5;
 
1451
            float r0 = gradient->startRadius() * scale;
 
1452
            float r1 = gradient->endRadius() * scale;
 
1453
            g_radialGradientFiller(dc, rect, p0, p1, r0, r1, gradient->getStops());
 
1454
            return;
 
1455
        }
 
1456
    } else if (g_linearGradientFiller) {
 
1457
        g_linearGradientFiller(dc, rect, p0, p1, gradient->getStops());
 
1458
        return;
 
1459
    }
 
1460
 
 
1461
    // Simple 1D linear solution that assumes p0 is on the top or left side, and p1 is on the right or bottom side
 
1462
    size_t numRects = (numStops - 1);
 
1463
    Vector<TRIVERTEX, 20> tv;
 
1464
    tv.resize(numRects * 2);
 
1465
    Vector<GRADIENT_RECT, 10> mesh;
 
1466
    mesh.resize(numRects);
 
1467
    int x = rect.x();
 
1468
    int y = rect.y();
 
1469
    int width = rect.width();
 
1470
    int height = rect.height();
 
1471
    FloatSize d = gradient->p1() - gradient->p0();
 
1472
    bool vertical = fabs(d.height()) > fabs(d.width());
 
1473
    for (size_t i = 0; i < numStops; ++i) {
 
1474
        const Gradient::ColorStop& stop = stops[i];
 
1475
        int iTv = i ? 2 * i - 1 : 0;
 
1476
        tv[iTv].Red = stop.red * 0xFFFF;
 
1477
        tv[iTv].Green = stop.green * 0xFFFF;
 
1478
        tv[iTv].Blue = stop.blue * 0xFFFF;
 
1479
        tv[iTv].Alpha = stop.alpha * 0xFFFF;
 
1480
        if (i) {
 
1481
            tv[iTv].x = vertical ? x + width: x + width * stop.stop;
 
1482
            tv[iTv].y = vertical ? y + height * stop.stop : y + height;
 
1483
            mesh[i - 1].UpperLeft = iTv - 1;
 
1484
            mesh[i - 1].LowerRight = iTv;
 
1485
        } else {
 
1486
            tv[iTv].x = x;
 
1487
            tv[iTv].y = y;
 
1488
        }
 
1489
 
 
1490
        if (i && i < numRects) {
 
1491
            tv[iTv + 1] = tv[iTv];
 
1492
            if (vertical)
 
1493
                tv[iTv + 1].x = x;
 
1494
            else
 
1495
                tv[iTv + 1].y = y;
 
1496
        }
 
1497
    }
 
1498
 
 
1499
    GradientFill(dc, tv.data(), tv.size(), mesh.data(), mesh.size(), vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
 
1500
}
 
1501
 
 
1502
AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
 
1503
{
 
1504
    if (paintingDisabled())
 
1505
        return AffineTransform();
 
1506
 
 
1507
    return m_data->m_transform;
 
1508
}
 
1509
 
 
1510
void GraphicsContext::fillRect(const FloatRect& rect)
 
1511
{
 
1512
    savePlatformState();
 
1513
 
 
1514
    if (m_state.fillGradient)
 
1515
        fillRect(rect, m_state.fillGradient.get());
 
1516
    else
 
1517
        fillRect(rect, fillColor(), ColorSpaceDeviceRGB);
 
1518
 
 
1519
    restorePlatformState();
 
1520
}
 
1521
 
 
1522
void GraphicsContext::setPlatformShadow(const FloatSize&, float, const Color&, ColorSpace)
 
1523
{
 
1524
    notImplemented();
 
1525
}
 
1526
 
 
1527
void GraphicsContext::clearPlatformShadow()
 
1528
{
 
1529
    notImplemented();
 
1530
}
 
1531
 
 
1532
InterpolationQuality GraphicsContext::imageInterpolationQuality() const
 
1533
{
 
1534
    notImplemented();
 
1535
    return InterpolationDefault;
 
1536
}
 
1537
 
 
1538
void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
 
1539
{
 
1540
    notImplemented();
 
1541
}
 
1542
 
 
1543
static inline bool isCharVisible(UChar c)
 
1544
{
 
1545
    return c && c != zeroWidthSpace;
 
1546
}
 
1547
 
 
1548
void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to)
 
1549
{
 
1550
    if (paintingDisabled() || !fillColor().alpha() || !m_data->m_opacity)
 
1551
        return;
 
1552
 
 
1553
    bool mustSupportAlpha = m_data->hasAlpha();
 
1554
 
 
1555
    if (!mustSupportAlpha && fillColor().alpha() == 0xFF && m_data->m_opacity >= 1.0) {
 
1556
        font.drawText(this, run, point, from, to);
 
1557
        return;
 
1558
    }
 
1559
 
 
1560
    float oldOpacity = m_data->m_opacity;
 
1561
    m_data->m_opacity *= fillColor().alpha() / 255.0;
 
1562
 
 
1563
    FloatRect textRect = font.selectionRectForText(run, point, font.fontMetrics().height(), from, to);
 
1564
    textRect.setY(textRect.y() - font.fontMetrics().ascent());
 
1565
    IntRect trRect = enclosingIntRect(m_data->mapRect(textRect));
 
1566
    RECT bmpRect;
 
1567
    AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone;
 
1568
    if (RefPtr<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) {
 
1569
        {
 
1570
            GraphicsContext gc(0);
 
1571
            gc.setBitmap(bmp);
 
1572
            gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d()));
 
1573
            font.drawText(&gc, run, IntPoint(0, font.fontMetrics().ascent()), from, to);
 
1574
        }
 
1575
        unsigned key1;
 
1576
        HDC memDC = bmp->getDC(&key1);
 
1577
        if (memDC) {
 
1578
            m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect);
 
1579
            bmp->releaseDC(memDC, key1);
 
1580
        }
 
1581
    }
 
1582
 
 
1583
    m_data->m_opacity = oldOpacity;
 
1584
}
 
1585
 
 
1586
void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
 
1587
                      int from, int numGlyphs, const FloatPoint& point)
 
1588
{
 
1589
    if (!m_data->m_opacity)
 
1590
        return;
 
1591
 
 
1592
    for (;;) {
 
1593
        if (!numGlyphs)
 
1594
            return;
 
1595
        if (isCharVisible(*glyphBuffer.glyphs(from)))
 
1596
            break;
 
1597
        ++from;
 
1598
        --numGlyphs;
 
1599
    }
 
1600
 
 
1601
    double scaleX = m_data->m_transform.a();
 
1602
    double scaleY = m_data->m_transform.d();
 
1603
 
 
1604
    int height = fontData->platformData().size() * scaleY;
 
1605
    int width = fontData->avgCharWidth() * scaleX;
 
1606
 
 
1607
    if (!height || !width)
 
1608
        return;
 
1609
 
 
1610
    ScopeDCProvider dcProvider(m_data);
 
1611
    if (!m_data->m_dc)
 
1612
        return;
 
1613
 
 
1614
    HFONT hFont = height > 1
 
1615
        ? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width)
 
1616
        : 0;
 
1617
 
 
1618
    FloatPoint startPoint(point.x(), point.y() - fontData->fontMetrics().ascent());
 
1619
    FloatPoint trPoint = m_data->mapPoint(startPoint);
 
1620
    int y = stableRound(trPoint.y());
 
1621
 
 
1622
    Color color = fillColor();
 
1623
    if (!color.alpha())
 
1624
        return;
 
1625
 
 
1626
    COLORREF fontColor = RGB(color.red(), color.green(), color.blue());
 
1627
 
 
1628
    if (!hFont) {
 
1629
        double offset = trPoint.x();
 
1630
        const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
 
1631
        if (scaleX == 1.)
 
1632
            for (int i = 1; i < numGlyphs; ++i)
 
1633
                offset += (*advance++).width();
 
1634
        else
 
1635
            for (int i = 1; i < numGlyphs; ++i)
 
1636
                offset += (*advance++).width() * scaleX;
 
1637
 
 
1638
        offset += width;
 
1639
 
 
1640
        OwnPtr<HPEN> hPen = adoptPtr(CreatePen(PS_DASH, 1, fontColor));
 
1641
        HGDIOBJ oldPen = SelectObject(m_data->m_dc, hPen.get());
 
1642
 
 
1643
        MoveToEx(m_data->m_dc, stableRound(trPoint.x()), y, 0);
 
1644
        LineTo(m_data->m_dc, stableRound(offset), y);
 
1645
 
 
1646
        SelectObject(m_data->m_dc, oldPen);
 
1647
        return;
 
1648
    }
 
1649
 
 
1650
    FloatSize shadowOffset;
 
1651
    float shadowBlur = 0;
 
1652
    Color shadowColor;
 
1653
    ColorSpace shadowColorSpace;
 
1654
    bool hasShadow = textDrawingMode() == TextModeFill
 
1655
        && getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)
 
1656
        && shadowColor.alpha();
 
1657
    COLORREF shadowRGBColor;
 
1658
    FloatPoint trShadowPoint;
 
1659
    if (hasShadow) {
 
1660
        shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue());
 
1661
        trShadowPoint = m_data->mapPoint(startPoint + shadowOffset);
 
1662
    }
 
1663
 
 
1664
    HGDIOBJ hOldFont = SelectObject(m_data->m_dc, hFont);
 
1665
    COLORREF oldTextColor = GetTextColor(m_data->m_dc);
 
1666
    int oldTextAlign = GetTextAlign(m_data->m_dc);
 
1667
    SetTextAlign(m_data->m_dc, 0);
 
1668
 
 
1669
    int oldBkMode = GetBkMode(m_data->m_dc);
 
1670
    SetBkMode(m_data->m_dc, TRANSPARENT);
 
1671
 
 
1672
    if (numGlyphs > 1) {
 
1673
        double offset = trPoint.x();
 
1674
        Vector<int, 256> glyphSpace(numGlyphs);
 
1675
        Vector<UChar, 256> text(numGlyphs);
 
1676
        int* curSpace = glyphSpace.data();
 
1677
        UChar* curChar = text.data();
 
1678
        const UChar* srcChar = glyphBuffer.glyphs(from);
 
1679
        const UChar* const srcCharEnd = srcChar + numGlyphs;
 
1680
        *curChar++ = *srcChar++;
 
1681
        int firstOffset = stableRound(offset);
 
1682
        int lastOffset = firstOffset;
 
1683
        const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
 
1684
        // FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off.
 
1685
        // (this can be GDI bug or font driver bug?)
 
1686
        // We are not clear how it processes characters and handles specified spaces. On the other side,
 
1687
        // our glyph buffer is already in the correct order for rendering. So, the solution is that we
 
1688
        // call ExtTextOut() for each single character when the text contains any RTL character.
 
1689
        // This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters.
 
1690
        // Drawing characters one by one may be too slow.
 
1691
        bool drawOneByOne = false;
 
1692
        if (scaleX == 1.) {
 
1693
            for (; srcChar < srcCharEnd; ++srcChar) {
 
1694
                offset += (*advance++).width();
 
1695
                int offsetInt = stableRound(offset);
 
1696
                if (isCharVisible(*srcChar)) {
 
1697
                    if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
 
1698
                        drawOneByOne = true;
 
1699
                    *curChar++ = *srcChar;
 
1700
                    *curSpace++ = offsetInt - lastOffset;
 
1701
                    lastOffset = offsetInt;
 
1702
                }
 
1703
            }
 
1704
        } else {
 
1705
            for (; srcChar < srcCharEnd; ++srcChar) {
 
1706
                offset += (*advance++).width() * scaleX;
 
1707
                int offsetInt = stableRound(offset);
 
1708
                if (isCharVisible(*srcChar)) {
 
1709
                    if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
 
1710
                        drawOneByOne = true;
 
1711
                    *curChar++ = *srcChar;
 
1712
                    *curSpace++ = offsetInt - lastOffset;
 
1713
                    lastOffset = offsetInt;
 
1714
                }
 
1715
            }
 
1716
        }
 
1717
        numGlyphs = curChar - text.data();
 
1718
        if (hasShadow) {
 
1719
            SetTextColor(m_data->m_dc, shadowRGBColor);
 
1720
            if (drawOneByOne) {
 
1721
                int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x());
 
1722
                int yShadow = stableRound(trShadowPoint.y());
 
1723
                for (int i = 0; i < numGlyphs; ++i) {
 
1724
                    ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0);
 
1725
                    xShadow += glyphSpace[i];
 
1726
                }
 
1727
            } else
 
1728
                ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data());
 
1729
        }
 
1730
        SetTextColor(m_data->m_dc, fontColor);
 
1731
        if (drawOneByOne) {
 
1732
            int x = firstOffset;
 
1733
            for (int i = 0; i < numGlyphs; ++i) {
 
1734
                ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0);
 
1735
                x += glyphSpace[i];
 
1736
            }
 
1737
        } else
 
1738
            ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data());
 
1739
    } else {
 
1740
        UChar c = *glyphBuffer.glyphs(from);
 
1741
        if (hasShadow) {
 
1742
            SetTextColor(m_data->m_dc, shadowRGBColor);
 
1743
            ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0);
 
1744
        }
 
1745
        SetTextColor(m_data->m_dc, fontColor);
 
1746
        ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0);
 
1747
    }
 
1748
 
 
1749
    SetTextAlign(m_data->m_dc, oldTextAlign);
 
1750
    SetTextColor(m_data->m_dc, oldTextColor);
 
1751
    SetBkMode(m_data->m_dc, oldBkMode);
 
1752
    SelectObject(m_data->m_dc, hOldFont);
 
1753
}
 
1754
 
 
1755
void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state)
 
1756
{
 
1757
    if (!m_data->m_opacity)
 
1758
        return;
 
1759
 
 
1760
    const int boxWidthBest = 8;
 
1761
    const int boxHeightBest = 8;
 
1762
 
 
1763
    ScopeDCProvider dcProvider(m_data);
 
1764
    if (!m_data->m_dc)
 
1765
        return;
 
1766
 
 
1767
    IntRect trRect = m_data->mapRect(rect);
 
1768
    TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true);
 
1769
    HDC dc = transparentDC.hdc();
 
1770
    if (!dc)
 
1771
        return;
 
1772
    trRect.move(transparentDC.toShift());
 
1773
 
 
1774
    RECT rectWin = trRect;
 
1775
 
 
1776
    if ((rectWin.right - rectWin.left) < boxWidthBest) {
 
1777
        RefPtr<SharedBitmap> bmp = SharedBitmap::create(IntSize(boxWidthBest, boxHeightBest), BitmapInfo::BitCount16, true);
 
1778
        SharedBitmap::DCHolder memDC(bmp.get());
 
1779
        if (memDC.get()) {
 
1780
            RECT tempRect = {0, 0, boxWidthBest, boxHeightBest};
 
1781
            DrawFrameControl(memDC.get(), &tempRect, type, state);
 
1782
 
 
1783
            ::StretchBlt(dc, rectWin.left, rectWin.top, rectWin.right - rectWin.left, rectWin.bottom - rectWin.top, memDC.get(), 0, 0, boxWidthBest, boxHeightBest, SRCCOPY);
 
1784
            return;
 
1785
        }
 
1786
    }
 
1787
 
 
1788
    DrawFrameControl(dc, &rectWin, type, state);
 
1789
}
 
1790
 
 
1791
void GraphicsContext::drawFocusRect(const IntRect& rect)
 
1792
{
 
1793
    if (!m_data->m_opacity)
 
1794
        return;
 
1795
 
 
1796
    ScopeDCProvider dcProvider(m_data);
 
1797
    if (!m_data->m_dc)
 
1798
        return;
 
1799
 
 
1800
    IntRect trRect = m_data->mapRect(rect);
 
1801
    TransparentLayerDC transparentDC(m_data, trRect, &rect);
 
1802
    HDC dc = transparentDC.hdc();
 
1803
    if (!dc)
 
1804
        return;
 
1805
    trRect.move(transparentDC.toShift());
 
1806
 
 
1807
    RECT rectWin = trRect;
 
1808
    DrawFocusRect(dc, &rectWin);
 
1809
}
 
1810
 
 
1811
void GraphicsContext::paintTextField(const IntRect& rect, unsigned state)
 
1812
{
 
1813
    if (!m_data->m_opacity)
 
1814
        return;
 
1815
 
 
1816
    ScopeDCProvider dcProvider(m_data);
 
1817
    if (!m_data->m_dc)
 
1818
        return;
 
1819
 
 
1820
    IntRect trRect = m_data->mapRect(rect);
 
1821
    TransparentLayerDC transparentDC(m_data, trRect, &rect);
 
1822
    HDC dc = transparentDC.hdc();
 
1823
    if (!dc)
 
1824
        return;
 
1825
    trRect.move(transparentDC.toShift());
 
1826
 
 
1827
    RECT rectWin = trRect;
 
1828
    DrawEdge(dc, &rectWin, EDGE_ETCHED, BF_RECT | BF_ADJUST);
 
1829
    FillRect(dc, &rectWin, reinterpret_cast<HBRUSH>(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
 
1830
}
 
1831
 
 
1832
void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
 
1833
{
 
1834
    if (!m_data->m_opacity)
 
1835
        return;
 
1836
 
 
1837
    ScopeDCProvider dcProvider(m_data);
 
1838
    if (!m_data->m_dc)
 
1839
        return;
 
1840
 
 
1841
    IntRect dstRect = m_data->mapRect(dstRectIn);
 
1842
    TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
 
1843
    HDC dc = transparentDC.hdc();
 
1844
    if (!dc)
 
1845
        return;
 
1846
    dstRect.move(transparentDC.toShift());
 
1847
 
 
1848
    bmp->draw(dc, dstRect, srcRect, compositeOp);
 
1849
 
 
1850
    if (bmp->is16bit())
 
1851
        transparentDC.fillAlphaChannel();
 
1852
}
 
1853
 
 
1854
void GraphicsContext::drawBitmapPattern(SharedBitmap* bmp, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
 
1855
                const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRectIn, const IntSize& origSourceSize)
 
1856
{
 
1857
    if (!m_data->m_opacity)
 
1858
        return;
 
1859
 
 
1860
    ScopeDCProvider dcProvider(m_data);
 
1861
    if (!m_data->m_dc)
 
1862
        return;
 
1863
 
 
1864
    IntRect intDstRect = enclosingIntRect(destRectIn);
 
1865
    IntRect trRect = m_data->mapRect(intDstRect);
 
1866
    TransparentLayerDC transparentDC(m_data, trRect, &intDstRect, 255, true);
 
1867
    HDC dc = transparentDC.hdc();
 
1868
    if (!dc)
 
1869
        return;
 
1870
    trRect.move(transparentDC.toShift());
 
1871
    FloatRect movedDstRect = m_data->m_transform.inverse().mapRect(FloatRect(trRect));
 
1872
    FloatSize moved(movedDstRect.location() - destRectIn.location());
 
1873
    AffineTransform transform = m_data->m_transform;
 
1874
    transform.translate(moved.width(), moved.height());
 
1875
 
 
1876
    bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, styleColorSpace, op, destRectIn, origSourceSize);
 
1877
 
 
1878
    if (!bmp->hasAlpha())
 
1879
        transparentDC.fillAlphaChannel();
 
1880
}
 
1881
 
 
1882
void GraphicsContext::drawIcon(HICON icon, const IntRect& dstRectIn, UINT flags)
 
1883
{
 
1884
    if (!m_data->m_opacity)
 
1885
        return;
 
1886
 
 
1887
    ScopeDCProvider dcProvider(m_data);
 
1888
    if (!m_data->m_dc)
 
1889
        return;
 
1890
 
 
1891
    IntRect dstRect = m_data->mapRect(dstRectIn);
 
1892
    TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
 
1893
    HDC dc = transparentDC.hdc();
 
1894
    if (!dc)
 
1895
        return;
 
1896
    dstRect.move(transparentDC.toShift());
 
1897
 
 
1898
    DrawIconEx(dc, dstRect.x(), dstRect.y(), icon, dstRect.width(), dstRect.height(), 0, NULL, flags);
 
1899
}
 
1900
 
 
1901
void GraphicsContext::setPlatformShouldAntialias(bool)
 
1902
{
 
1903
    notImplemented();
 
1904
}
 
1905
 
 
1906
void GraphicsContext::setLineDash(const DashArray&, float)
 
1907
{
 
1908
    notImplemented();
 
1909
}
 
1910
 
 
1911
void GraphicsContext::clipPath(const Path&, WindRule)
 
1912
{
 
1913
    notImplemented();
 
1914
}
 
1915
 
 
1916
} // namespace WebCore