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