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
39namespace WebCore {
40
41typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops);
42typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops);
43FuncGradientFillRectLinear g_linearGradientFiller = 0;
44FuncGradientFillRectRadial g_radialGradientFiller = 0;
45
46static 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.
52static 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.
62static 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
68class RotationTransform {
69public:
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
113template<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
120template<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
127template<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
154template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform)
155{
156    return mapRect<T, IntRect, int>(rect, transform);
157}
158
159template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform)
160{
161    return mapRect<T, FloatRect, double>(rect, transform);
162}
163
164class GraphicsContextPlatformPrivateData {
165public:
166    GraphicsContextPlatformPrivateData()
167        : m_transform()
168        , m_opacity(1.0)
169    {
170    }
171
172    AffineTransform m_transform;
173    float m_opacity;
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    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
348static 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
375static inline PassOwnPtr<HBRUSH> createBrush(const Color& col)
376{
377    return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue())));
378}
379
380template <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
440static 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
449class TransparentLayerDC {
450    WTF_MAKE_NONCOPYABLE(TransparentLayerDC);
451public:
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
460private:
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
474TransparentLayerDC::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
541TransparentLayerDC::~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
557void 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
570class ScopeDCProvider {
571    WTF_MAKE_NONCOPYABLE(ScopeDCProvider);
572public:
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    }
586private:
587    GraphicsContextPlatformPrivate* m_data;
588    unsigned m_key;
589};
590
591
592void GraphicsContext::platformInit(PlatformGraphicsContext* dc)
593{
594    m_data = new GraphicsContextPlatformPrivate(dc);
595}
596
597void GraphicsContext::platformDestroy()
598{
599    delete m_data;
600}
601
602void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp)
603{
604    ASSERT(!m_data->m_dc);
605    m_data->m_bitmap = bmp;
606}
607
608HDC 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
615void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
616{
617}
618
619void GraphicsContext::savePlatformState()
620{
621    m_data->save();
622}
623
624void GraphicsContext::restorePlatformState()
625{
626    m_data->restore();
627}
628
629void 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
674void 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
704void 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
743static inline bool equalAngle(double a, double b)
744{
745    return fabs(a - b) < 1E-5;
746}
747
748void 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
786void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
787{
788    if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points)
789        return;
790
791    ScopeDCProvider dcProvider(m_data);
792    if (!m_data->m_dc)
793        return;
794
795    Vector<POINT, 20> winPoints(npoints);
796    FloatPoint trPoint = m_data->mapPoint(points[0]);
797    winPoints[0].x = stableRound(trPoint.x());
798    winPoints[0].y = stableRound(trPoint.y());
799    RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y };
800    for (size_t i = 1; i < npoints; ++i) {
801        trPoint = m_data->mapPoint(points[i]);
802        winPoints[i].x = stableRound(trPoint.x());
803        winPoints[i].y = stableRound(trPoint.y());
804        if (rect.left > winPoints[i].x)
805            rect.left = winPoints[i].x;
806        else if (rect.right < winPoints[i].x)
807            rect.right = winPoints[i].x;
808        if (rect.top > winPoints[i].y)
809            rect.top = winPoints[i].y;
810        else if (rect.bottom < winPoints[i].y)
811            rect.bottom = winPoints[i].y;
812    }
813    rect.bottom += 1;
814    rect.right += 1;
815
816    IntRect intRect(rect);
817    TransparentLayerDC transparentDC(m_data, intRect);
818    HDC dc = transparentDC.hdc();
819    if (!dc)
820        return;
821
822    for (size_t i = 0; i < npoints; ++i) {
823        winPoints[i].x += transparentDC.toShift().width();
824        winPoints[i].y += transparentDC.toShift().height();
825    }
826
827    OwnPtr<HBRUSH> brush;
828    HGDIOBJ oldBrush;
829    if (fillColor().alpha()) {
830        brush = createBrush(fillColor());
831        oldBrush = SelectObject(dc, brush.get());
832    } else
833        oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
834
835    OwnPtr<HPEN> pen;
836    HGDIOBJ oldPen;
837    if (strokeStyle() != NoStroke) {
838        pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
839        oldPen = SelectObject(dc, pen.get());
840    } else
841        oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
842
843    if (brush || pen)
844        Polygon(dc, winPoints.data(), npoints);
845
846    SelectObject(dc, oldPen);
847    SelectObject(dc, oldBrush);
848}
849
850void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
851{
852    if (paintingDisabled())
853        return;
854
855    if (numPoints <= 1)
856        return;
857
858    // FIXME: IMPLEMENT!!
859}
860
861void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
862{
863    if (paintingDisabled() || !m_data->m_opacity)
864        return;
865
866    int alpha = color.alpha();
867    if (!alpha)
868        return;
869
870    ScopeDCProvider dcProvider(m_data);
871    if (!m_data->m_dc)
872        return;
873
874    IntRect intRect = enclosingIntRect(rect);
875    TransparentLayerDC transparentDC(m_data, m_data->mapRect(intRect), &intRect, alpha);
876
877    if (!transparentDC.hdc())
878        return;
879
880    OwnPtr<HBRUSH> hbrush = adoptPtr(CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
881    FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get());
882}
883
884void GraphicsContext::clip(const FloatRect& rect)
885{
886    if (paintingDisabled())
887        return;
888
889    if (!m_data->m_dc)
890        return;
891
892    IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
893
894    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
895    if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0)
896        IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
897    else {
898        clipRgn = adoptPtr(CreateRectRgn(trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()));
899        SelectClipRgn(m_data->m_dc, clipRgn.get());
900    }
901}
902
903void GraphicsContext::clipOut(const IntRect& rect)
904{
905    if (paintingDisabled())
906        return;
907
908    if (!m_data->m_dc)
909        return;
910
911    IntRect trRect = m_data->mapRect(rect);
912
913    ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
914}
915
916void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
917{
918    // FIXME: implement
919}
920
921void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
922{
923    if (!m_data->m_opacity || paintingDisabled())
924        return;
925
926    ScopeDCProvider dcProvider(m_data);
927    if (!m_data->m_dc)
928        return;
929
930    int radius = (width - 1) / 2;
931    offset += radius;
932
933    unsigned rectCount = rects.size();
934    IntRect finalFocusRect;
935    for (unsigned i = 0; i < rectCount; i++) {
936        IntRect focusRect = rects[i];
937        focusRect.inflate(offset);
938        finalFocusRect.unite(focusRect);
939    }
940
941    IntRect intRect = finalFocusRect;
942    IntRect trRect = m_data->mapRect(finalFocusRect);
943    TransparentLayerDC transparentDC(m_data, trRect, &intRect);
944    HDC dc = transparentDC.hdc();
945    if (!dc)
946        return;
947    trRect.move(transparentDC.toShift());
948
949    RECT rect = trRect;
950    DrawFocusRect(dc, &rect);
951}
952
953void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing)
954{
955    if (paintingDisabled())
956        return;
957
958    StrokeStyle oldStyle = strokeStyle();
959    setStrokeStyle(SolidStroke);
960    drawLine(roundedIntPoint(origin), roundedIntPoint(origin + FloatSize(width, 0)));
961    setStrokeStyle(oldStyle);
962}
963
964void GraphicsContext::drawLineForDocumentMarker(const FloatPoint&, float width, DocumentMarkerLineStyle style)
965{
966    notImplemented();
967}
968
969void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
970{
971    notImplemented();
972}
973
974void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
975{
976    notImplemented();
977}
978
979void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
980{
981    notImplemented();
982}
983
984void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
985{
986    notImplemented();
987}
988
989void GraphicsContext::clearRect(const FloatRect& rect)
990{
991    if (paintingDisabled())
992        return;
993
994    if (m_data->hasAlpha()) {
995        IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
996        m_data->m_bitmap->clearPixels(trRect);
997        return;
998    }
999
1000    fillRect(rect, Color(Color::white), ColorSpaceDeviceRGB);
1001}
1002
1003void GraphicsContext::strokeRect(const FloatRect& rect, float width)
1004{
1005    if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke)
1006        return;
1007
1008    ScopeDCProvider dcProvider(m_data);
1009    if (!m_data->m_dc)
1010        return;
1011
1012    IntRect intRect = enclosingIntRect(rect);
1013    IntRect trRect = m_data->mapRect(intRect);
1014    TransparentLayerDC transparentDC(m_data, trRect, &intRect);
1015    HDC dc = transparentDC.hdc();
1016    if (!dc)
1017        return;
1018    trRect.move(transparentDC.toShift());
1019
1020    OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
1021    HGDIOBJ oldPen = SelectObject(dc, pen.get());
1022
1023    int right = trRect.maxX() - 1;
1024    int bottom = trRect.maxY() - 1;
1025    const POINT intPoints[5] =
1026    {
1027        { trRect.x(), trRect.y() },
1028        { right, trRect.y() },
1029        { right, bottom },
1030        { trRect.x(), bottom },
1031        { trRect.x(), trRect.y() }
1032    };
1033
1034    Polyline(dc, intPoints, 5);
1035
1036    SelectObject(dc, oldPen);
1037}
1038
1039void GraphicsContext::beginPlatformTransparencyLayer(float opacity)
1040{
1041    m_data->save();
1042    m_data->m_opacity *= opacity;
1043}
1044
1045void GraphicsContext::endPlatformTransparencyLayer()
1046{
1047    m_data->restore();
1048}
1049
1050bool GraphicsContext::supportsTransparencyLayers()
1051{
1052    return true;
1053}
1054
1055void GraphicsContext::concatCTM(const AffineTransform& transform)
1056{
1057    m_data->concatCTM(transform);
1058}
1059
1060void GraphicsContext::setCTM(const AffineTransform& transform)
1061{
1062    m_data->setCTM(transform);
1063}
1064
1065AffineTransform& GraphicsContext::affineTransform()
1066{
1067    return m_data->m_transform;
1068}
1069
1070const AffineTransform& GraphicsContext::affineTransform() const
1071{
1072    return m_data->m_transform;
1073}
1074
1075void GraphicsContext::resetAffineTransform()
1076{
1077    m_data->m_transform.makeIdentity();
1078}
1079
1080void GraphicsContext::translate(float x, float y)
1081{
1082    m_data->translate(x, y);
1083}
1084
1085void GraphicsContext::rotate(float radians)
1086{
1087    m_data->rotate(radians);
1088}
1089
1090void GraphicsContext::scale(const FloatSize& size)
1091{
1092    m_data->scale(size);
1093}
1094
1095void GraphicsContext::setLineCap(LineCap lineCap)
1096{
1097    notImplemented();
1098}
1099
1100void GraphicsContext::setLineJoin(LineJoin lineJoin)
1101{
1102    notImplemented();
1103}
1104
1105void GraphicsContext::setMiterLimit(float miter)
1106{
1107    notImplemented();
1108}
1109
1110void GraphicsContext::setAlpha(float alpha)
1111{
1112    m_data->m_opacity = alpha;
1113}
1114
1115void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op, BlendMode blendMode)
1116{
1117    notImplemented();
1118}
1119
1120void GraphicsContext::clip(const Path& path, WindRule)
1121{
1122    notImplemented();
1123}
1124
1125void GraphicsContext::canvasClip(const Path& path, WindRule fillRule)
1126{
1127    clip(path, fillRule);
1128}
1129
1130void GraphicsContext::clipOut(const Path&)
1131{
1132    notImplemented();
1133}
1134
1135static inline IntPoint rectCenterPoint(const RECT& rect)
1136{
1137    return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2);
1138}
1139void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace)
1140{
1141    ScopeDCProvider dcProvider(m_data);
1142    if (!m_data->m_dc)
1143        return;
1144
1145    FloatSize shadowOffset;
1146    float shadowBlur = 0;
1147    Color shadowColor;
1148    ColorSpace shadowColorSpace;
1149
1150    getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
1151
1152    IntRect dstRect = fillRect;
1153
1154    dstRect.move(stableRound(shadowOffset.width()), stableRound(shadowOffset.height()));
1155    dstRect.inflate(stableRound(shadowBlur));
1156    dstRect = m_data->mapRect(dstRect);
1157
1158    FloatSize newTopLeft(m_data->mapSize(topLeft));
1159    FloatSize newTopRight(m_data->mapSize(topRight));
1160    FloatSize newBottomLeft(m_data->mapSize(bottomLeft));
1161    FloatSize newBottomRight(m_data->mapSize(bottomRight));
1162
1163    TransparentLayerDC transparentDc(m_data, dstRect, &fillRect);
1164    HDC dc = transparentDc.hdc();
1165    if (!dc)
1166        return;
1167
1168    dstRect.move(transparentDc.toShift());
1169
1170    RECT rectWin = dstRect;
1171
1172    OwnPtr<HBRUSH> brush = createBrush(shadowColor);
1173    HGDIOBJ oldBrush = SelectObject(dc, brush.get());
1174
1175    SelectObject(dc, GetStockObject(NULL_PEN));
1176
1177    IntPoint centerPoint = rectCenterPoint(rectWin);
1178    // Draw top left half
1179    RECT clipRect(rectWin);
1180    clipRect.right = centerPoint.x();
1181    clipRect.bottom = centerPoint.y();
1182
1183    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
1184    bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0);
1185
1186    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2));
1187
1188    // Draw top right
1189    clipRect = rectWin;
1190    clipRect.left = centerPoint.x();
1191    clipRect.bottom = centerPoint.y();
1192
1193    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2));
1194
1195     // Draw bottom left
1196    clipRect = rectWin;
1197    clipRect.right = centerPoint.x();
1198    clipRect.top = centerPoint.y();
1199
1200    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2));
1201
1202    // Draw bottom right
1203    clipRect = rectWin;
1204    clipRect.left = centerPoint.x();
1205    clipRect.top = centerPoint.y();
1206
1207    drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
1208
1209    SelectObject(dc, oldBrush);
1210}
1211
1212
1213void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height)
1214{
1215    if (!dc)
1216        return;
1217
1218    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
1219    if (needsNewClip) {
1220        clipRgn = adoptPtr(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
1221        SelectClipRgn(dc, clipRgn.get());
1222    } else
1223        IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1224
1225    ::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height);
1226
1227    SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get());
1228}
1229
1230
1231FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
1232{
1233    notImplemented();
1234    return frect;
1235}
1236
1237Color gradientAverageColor(const Gradient* gradient)
1238{
1239    const Vector<Gradient::ColorStop>& stops = gradient->getStops();
1240    if (stops.isEmpty())
1241        return Color();
1242
1243    const Gradient::ColorStop& stop = stops.first();
1244    if (stops.size() == 1)
1245        return Color(stop.red, stop.green, stop.blue, stop.alpha);
1246
1247    const Gradient::ColorStop& lastStop = stops.last();
1248    return Color((stop.red + lastStop.red) * 0.5f
1249        , (stop.green + lastStop.green) * 0.5f
1250        , (stop.blue + lastStop.blue) * 0.5f
1251        , (stop.alpha + lastStop.alpha) * 0.5f);
1252}
1253
1254void GraphicsContext::fillPath(const Path& path)
1255{
1256    if (path.isNull())
1257        return;
1258
1259    Color c = m_state.fillGradient
1260        ? gradientAverageColor(m_state.fillGradient.get())
1261        : fillColor();
1262
1263    if (!c.alpha() || !m_data->m_opacity)
1264        return;
1265
1266    ScopeDCProvider dcProvider(m_data);
1267    if (!m_data->m_dc)
1268        return;
1269
1270    OwnPtr<HBRUSH> brush = createBrush(c);
1271
1272    if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
1273        IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
1274        trRect.inflate(1);
1275        TransparentLayerDC transparentDC(m_data, trRect);
1276        HDC dc = transparentDC.hdc();
1277        if (!dc)
1278            return;
1279
1280        AffineTransform tr = m_data->m_transform;
1281        tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
1282
1283        SelectObject(dc, GetStockObject(NULL_PEN));
1284        HGDIOBJ oldBrush = SelectObject(dc, brush.get());
1285        path.platformPath()->fillPath(dc, &tr);
1286        SelectObject(dc, oldBrush);
1287    } else {
1288        SelectObject(m_data->m_dc, GetStockObject(NULL_PEN));
1289        HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get());
1290        path.platformPath()->fillPath(m_data->m_dc, &m_data->m_transform);
1291        SelectObject(m_data->m_dc, oldBrush);
1292    }
1293}
1294
1295
1296void GraphicsContext::strokePath(const Path& path)
1297{
1298    if (path.isNull() || !m_data->m_opacity)
1299        return;
1300
1301    ScopeDCProvider dcProvider(m_data);
1302    if (!m_data->m_dc)
1303        return;
1304
1305    OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
1306
1307    if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
1308        IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
1309        trRect.inflate(1);
1310        TransparentLayerDC transparentDC(m_data, trRect);
1311        HDC dc = transparentDC.hdc();
1312        if (!dc)
1313            return;
1314
1315        AffineTransform tr = m_data->m_transform;
1316        tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
1317
1318        SelectObject(dc, GetStockObject(NULL_BRUSH));
1319        HGDIOBJ oldPen = SelectObject(dc, pen.get());
1320        path.platformPath()->strokePath(dc, &tr);
1321        SelectObject(dc, oldPen);
1322    } else {
1323        SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH));
1324        HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get());
1325        path.platformPath()->strokePath(m_data->m_dc, &m_data->m_transform);
1326        SelectObject(m_data->m_dc, oldPen);
1327    }
1328}
1329
1330void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient)
1331{
1332    if (!m_data->m_opacity)
1333        return;
1334
1335    const Vector<Gradient::ColorStop>& stops = gradient->getStops();
1336    if (stops.isEmpty())
1337        return;
1338
1339    size_t numStops = stops.size();
1340    if (numStops == 1) {
1341        const Gradient::ColorStop& stop = stops.first();
1342        Color color(stop.red, stop.green, stop.blue, stop.alpha);
1343        fillRect(r, color, ColorSpaceDeviceRGB);
1344        return;
1345    }
1346
1347    ScopeDCProvider dcProvider(m_data);
1348    if (!m_data->m_dc)
1349        return;
1350
1351    IntRect intRect = enclosingIntRect(r);
1352    IntRect rect = m_data->mapRect(intRect);
1353    TransparentLayerDC transparentDC(m_data, rect, &intRect, 255, true);
1354    HDC dc = transparentDC.hdc();
1355    if (!dc)
1356        return;
1357
1358    rect.move(transparentDC.toShift());
1359    FloatPoint fp0 = m_data->mapPoint(gradient->p0());
1360    FloatPoint fp1 = m_data->mapPoint(gradient->p1());
1361    IntPoint p0(stableRound(fp0.x()), stableRound(fp0.y()));
1362    IntPoint p1(stableRound(fp1.x()), stableRound(fp1.y()));
1363    p0 += transparentDC.toShift();
1364    p1 += transparentDC.toShift();
1365
1366    if (gradient->isRadial()) {
1367        if (g_radialGradientFiller) {
1368            // FIXME: don't support 2D scaling at this time
1369            double scale = (m_data->m_transform.a() + m_data->m_transform.d()) * 0.5;
1370            float r0 = gradient->startRadius() * scale;
1371            float r1 = gradient->endRadius() * scale;
1372            g_radialGradientFiller(dc, rect, p0, p1, r0, r1, gradient->getStops());
1373            return;
1374        }
1375    } else if (g_linearGradientFiller) {
1376        g_linearGradientFiller(dc, rect, p0, p1, gradient->getStops());
1377        return;
1378    }
1379
1380    // Simple 1D linear solution that assumes p0 is on the top or left side, and p1 is on the right or bottom side
1381    size_t numRects = (numStops - 1);
1382    Vector<TRIVERTEX, 20> tv;
1383    tv.resize(numRects * 2);
1384    Vector<GRADIENT_RECT, 10> mesh;
1385    mesh.resize(numRects);
1386    int x = rect.x();
1387    int y = rect.y();
1388    int width = rect.width();
1389    int height = rect.height();
1390    FloatSize d = gradient->p1() - gradient->p0();
1391    bool vertical = fabs(d.height()) > fabs(d.width());
1392    for (size_t i = 0; i < numStops; ++i) {
1393        const Gradient::ColorStop& stop = stops[i];
1394        int iTv = i ? 2 * i - 1 : 0;
1395        tv[iTv].Red = stop.red * 0xFFFF;
1396        tv[iTv].Green = stop.green * 0xFFFF;
1397        tv[iTv].Blue = stop.blue * 0xFFFF;
1398        tv[iTv].Alpha = stop.alpha * 0xFFFF;
1399        if (i) {
1400            tv[iTv].x = vertical ? x + width: x + width * stop.stop;
1401            tv[iTv].y = vertical ? y + height * stop.stop : y + height;
1402            mesh[i - 1].UpperLeft = iTv - 1;
1403            mesh[i - 1].LowerRight = iTv;
1404        } else {
1405            tv[iTv].x = x;
1406            tv[iTv].y = y;
1407        }
1408
1409        if (i && i < numRects) {
1410            tv[iTv + 1] = tv[iTv];
1411            if (vertical)
1412                tv[iTv + 1].x = x;
1413            else
1414                tv[iTv + 1].y = y;
1415        }
1416    }
1417
1418    GradientFill(dc, tv.data(), tv.size(), mesh.data(), mesh.size(), vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
1419}
1420
1421AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
1422{
1423    if (paintingDisabled())
1424        return AffineTransform();
1425
1426    return m_data->m_transform;
1427}
1428
1429void GraphicsContext::fillRect(const FloatRect& rect)
1430{
1431    savePlatformState();
1432
1433    if (m_state.fillGradient)
1434        fillRect(rect, m_state.fillGradient.get());
1435    else
1436        fillRect(rect, fillColor(), ColorSpaceDeviceRGB);
1437
1438    restorePlatformState();
1439}
1440
1441void GraphicsContext::setPlatformShadow(const FloatSize&, float, const Color&, ColorSpace)
1442{
1443    notImplemented();
1444}
1445
1446void GraphicsContext::clearPlatformShadow()
1447{
1448    notImplemented();
1449}
1450
1451InterpolationQuality GraphicsContext::imageInterpolationQuality() const
1452{
1453    notImplemented();
1454    return InterpolationDefault;
1455}
1456
1457void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
1458{
1459    notImplemented();
1460}
1461
1462static inline bool isCharVisible(UChar c)
1463{
1464    return c && c != zeroWidthSpace;
1465}
1466
1467void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to)
1468{
1469    if (paintingDisabled() || !fillColor().alpha() || !m_data->m_opacity)
1470        return;
1471
1472    bool mustSupportAlpha = m_data->hasAlpha();
1473
1474    if (!mustSupportAlpha && fillColor().alpha() == 0xFF && m_data->m_opacity >= 1.0) {
1475        font.drawText(this, run, point, from, to);
1476        return;
1477    }
1478
1479    float oldOpacity = m_data->m_opacity;
1480    m_data->m_opacity *= fillColor().alpha() / 255.0;
1481
1482    FloatRect textRect = font.selectionRectForText(run, point, font.fontMetrics().height(), from, to);
1483    textRect.setY(textRect.y() - font.fontMetrics().ascent());
1484    IntRect trRect = enclosingIntRect(m_data->mapRect(textRect));
1485    RECT bmpRect;
1486    AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone;
1487    if (RefPtr<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) {
1488        {
1489            GraphicsContext gc(0);
1490            gc.setBitmap(bmp);
1491            gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d()));
1492            font.drawText(&gc, run, IntPoint(0, font.fontMetrics().ascent()), from, to);
1493        }
1494        unsigned key1;
1495        HDC memDC = bmp->getDC(&key1);
1496        if (memDC) {
1497            m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect);
1498            bmp->releaseDC(memDC, key1);
1499        }
1500    }
1501
1502    m_data->m_opacity = oldOpacity;
1503}
1504
1505void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
1506                      int from, int numGlyphs, const FloatPoint& point)
1507{
1508    if (!m_data->m_opacity)
1509        return;
1510
1511    for (;;) {
1512        if (!numGlyphs)
1513            return;
1514        if (isCharVisible(*glyphBuffer.glyphs(from)))
1515            break;
1516        ++from;
1517        --numGlyphs;
1518    }
1519
1520    double scaleX = m_data->m_transform.a();
1521    double scaleY = m_data->m_transform.d();
1522
1523    int height = fontData->platformData().size() * scaleY;
1524    int width = fontData->avgCharWidth() * scaleX;
1525
1526    if (!height || !width)
1527        return;
1528
1529    ScopeDCProvider dcProvider(m_data);
1530    if (!m_data->m_dc)
1531        return;
1532
1533    HFONT hFont = height > 1
1534        ? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width)
1535        : 0;
1536
1537    FloatPoint startPoint(point.x(), point.y() - fontData->fontMetrics().ascent());
1538    FloatPoint trPoint = m_data->mapPoint(startPoint);
1539    int y = stableRound(trPoint.y());
1540
1541    Color color = fillColor();
1542    if (!color.alpha())
1543        return;
1544
1545    COLORREF fontColor = RGB(color.red(), color.green(), color.blue());
1546
1547    if (!hFont) {
1548        double offset = trPoint.x();
1549        const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
1550        if (scaleX == 1.)
1551            for (int i = 1; i < numGlyphs; ++i)
1552                offset += (*advance++).width();
1553        else
1554            for (int i = 1; i < numGlyphs; ++i)
1555                offset += (*advance++).width() * scaleX;
1556
1557        offset += width;
1558
1559        OwnPtr<HPEN> hPen = adoptPtr(CreatePen(PS_DASH, 1, fontColor));
1560        HGDIOBJ oldPen = SelectObject(m_data->m_dc, hPen.get());
1561
1562        MoveToEx(m_data->m_dc, stableRound(trPoint.x()), y, 0);
1563        LineTo(m_data->m_dc, stableRound(offset), y);
1564
1565        SelectObject(m_data->m_dc, oldPen);
1566        return;
1567    }
1568
1569    FloatSize shadowOffset;
1570    float shadowBlur = 0;
1571    Color shadowColor;
1572    ColorSpace shadowColorSpace;
1573    bool hasShadow = textDrawingMode() == TextModeFill
1574        && getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)
1575        && shadowColor.alpha();
1576    COLORREF shadowRGBColor;
1577    FloatPoint trShadowPoint;
1578    if (hasShadow) {
1579        shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue());
1580        trShadowPoint = m_data->mapPoint(startPoint + shadowOffset);
1581    }
1582
1583    HGDIOBJ hOldFont = SelectObject(m_data->m_dc, hFont);
1584    COLORREF oldTextColor = GetTextColor(m_data->m_dc);
1585    int oldTextAlign = GetTextAlign(m_data->m_dc);
1586    SetTextAlign(m_data->m_dc, 0);
1587
1588    int oldBkMode = GetBkMode(m_data->m_dc);
1589    SetBkMode(m_data->m_dc, TRANSPARENT);
1590
1591    if (numGlyphs > 1) {
1592        double offset = trPoint.x();
1593        Vector<int, 256> glyphSpace(numGlyphs);
1594        Vector<UChar, 256> text(numGlyphs);
1595        int* curSpace = glyphSpace.data();
1596        UChar* curChar = text.data();
1597        const UChar* srcChar = glyphBuffer.glyphs(from);
1598        const UChar* const srcCharEnd = srcChar + numGlyphs;
1599        *curChar++ = *srcChar++;
1600        int firstOffset = stableRound(offset);
1601        int lastOffset = firstOffset;
1602        const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
1603        // FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off.
1604        // (this can be GDI bug or font driver bug?)
1605        // We are not clear how it processes characters and handles specified spaces. On the other side,
1606        // our glyph buffer is already in the correct order for rendering. So, the solution is that we
1607        // call ExtTextOut() for each single character when the text contains any RTL character.
1608        // This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters.
1609        // Drawing characters one by one may be too slow.
1610        bool drawOneByOne = false;
1611        if (scaleX == 1.) {
1612            for (; srcChar < srcCharEnd; ++srcChar) {
1613                offset += (*advance++).width();
1614                int offsetInt = stableRound(offset);
1615                if (isCharVisible(*srcChar)) {
1616                    if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
1617                        drawOneByOne = true;
1618                    *curChar++ = *srcChar;
1619                    *curSpace++ = offsetInt - lastOffset;
1620                    lastOffset = offsetInt;
1621                }
1622            }
1623        } else {
1624            for (; srcChar < srcCharEnd; ++srcChar) {
1625                offset += (*advance++).width() * scaleX;
1626                int offsetInt = stableRound(offset);
1627                if (isCharVisible(*srcChar)) {
1628                    if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
1629                        drawOneByOne = true;
1630                    *curChar++ = *srcChar;
1631                    *curSpace++ = offsetInt - lastOffset;
1632                    lastOffset = offsetInt;
1633                }
1634            }
1635        }
1636        numGlyphs = curChar - text.data();
1637        if (hasShadow) {
1638            SetTextColor(m_data->m_dc, shadowRGBColor);
1639            if (drawOneByOne) {
1640                int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x());
1641                int yShadow = stableRound(trShadowPoint.y());
1642                for (int i = 0; i < numGlyphs; ++i) {
1643                    ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0);
1644                    xShadow += glyphSpace[i];
1645                }
1646            } else
1647                ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data());
1648        }
1649        SetTextColor(m_data->m_dc, fontColor);
1650        if (drawOneByOne) {
1651            int x = firstOffset;
1652            for (int i = 0; i < numGlyphs; ++i) {
1653                ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0);
1654                x += glyphSpace[i];
1655            }
1656        } else
1657            ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data());
1658    } else {
1659        UChar c = *glyphBuffer.glyphs(from);
1660        if (hasShadow) {
1661            SetTextColor(m_data->m_dc, shadowRGBColor);
1662            ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0);
1663        }
1664        SetTextColor(m_data->m_dc, fontColor);
1665        ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0);
1666    }
1667
1668    SetTextAlign(m_data->m_dc, oldTextAlign);
1669    SetTextColor(m_data->m_dc, oldTextColor);
1670    SetBkMode(m_data->m_dc, oldBkMode);
1671    SelectObject(m_data->m_dc, hOldFont);
1672}
1673
1674void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state)
1675{
1676    if (!m_data->m_opacity)
1677        return;
1678
1679    const int boxWidthBest = 8;
1680    const int boxHeightBest = 8;
1681
1682    ScopeDCProvider dcProvider(m_data);
1683    if (!m_data->m_dc)
1684        return;
1685
1686    IntRect trRect = m_data->mapRect(rect);
1687    TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true);
1688    HDC dc = transparentDC.hdc();
1689    if (!dc)
1690        return;
1691    trRect.move(transparentDC.toShift());
1692
1693    RECT rectWin = trRect;
1694
1695    if ((rectWin.right - rectWin.left) < boxWidthBest) {
1696        RefPtr<SharedBitmap> bmp = SharedBitmap::create(IntSize(boxWidthBest, boxHeightBest), BitmapInfo::BitCount16, true);
1697        SharedBitmap::DCHolder memDC(bmp.get());
1698        if (memDC.get()) {
1699            RECT tempRect = {0, 0, boxWidthBest, boxHeightBest};
1700            DrawFrameControl(memDC.get(), &tempRect, type, state);
1701
1702            ::StretchBlt(dc, rectWin.left, rectWin.top, rectWin.right - rectWin.left, rectWin.bottom - rectWin.top, memDC.get(), 0, 0, boxWidthBest, boxHeightBest, SRCCOPY);
1703            return;
1704        }
1705    }
1706
1707    DrawFrameControl(dc, &rectWin, type, state);
1708}
1709
1710void GraphicsContext::drawFocusRect(const IntRect& rect)
1711{
1712    if (!m_data->m_opacity)
1713        return;
1714
1715    ScopeDCProvider dcProvider(m_data);
1716    if (!m_data->m_dc)
1717        return;
1718
1719    IntRect trRect = m_data->mapRect(rect);
1720    TransparentLayerDC transparentDC(m_data, trRect, &rect);
1721    HDC dc = transparentDC.hdc();
1722    if (!dc)
1723        return;
1724    trRect.move(transparentDC.toShift());
1725
1726    RECT rectWin = trRect;
1727    DrawFocusRect(dc, &rectWin);
1728}
1729
1730void GraphicsContext::paintTextField(const IntRect& rect, unsigned state)
1731{
1732    if (!m_data->m_opacity)
1733        return;
1734
1735    ScopeDCProvider dcProvider(m_data);
1736    if (!m_data->m_dc)
1737        return;
1738
1739    IntRect trRect = m_data->mapRect(rect);
1740    TransparentLayerDC transparentDC(m_data, trRect, &rect);
1741    HDC dc = transparentDC.hdc();
1742    if (!dc)
1743        return;
1744    trRect.move(transparentDC.toShift());
1745
1746    RECT rectWin = trRect;
1747    DrawEdge(dc, &rectWin, EDGE_ETCHED, BF_RECT | BF_ADJUST);
1748    FillRect(dc, &rectWin, reinterpret_cast<HBRUSH>(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
1749}
1750
1751void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode)
1752{
1753    if (!m_data->m_opacity)
1754        return;
1755
1756    ScopeDCProvider dcProvider(m_data);
1757    if (!m_data->m_dc)
1758        return;
1759
1760    IntRect dstRect = m_data->mapRect(dstRectIn);
1761    TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
1762    HDC dc = transparentDC.hdc();
1763    if (!dc)
1764        return;
1765    dstRect.move(transparentDC.toShift());
1766
1767    bmp->draw(dc, dstRect, srcRect, compositeOp, blendMode);
1768
1769    if (bmp->is16bit())
1770        transparentDC.fillAlphaChannel();
1771}
1772
1773void GraphicsContext::drawBitmapPattern(SharedBitmap* bmp, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
1774                const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRectIn, const IntSize& origSourceSize)
1775{
1776    if (!m_data->m_opacity)
1777        return;
1778
1779    ScopeDCProvider dcProvider(m_data);
1780    if (!m_data->m_dc)
1781        return;
1782
1783    IntRect intDstRect = enclosingIntRect(destRectIn);
1784    IntRect trRect = m_data->mapRect(intDstRect);
1785    TransparentLayerDC transparentDC(m_data, trRect, &intDstRect, 255, true);
1786    HDC dc = transparentDC.hdc();
1787    if (!dc)
1788        return;
1789    trRect.move(transparentDC.toShift());
1790    FloatRect movedDstRect = m_data->m_transform.inverse().mapRect(FloatRect(trRect));
1791    FloatSize moved(movedDstRect.location() - destRectIn.location());
1792    AffineTransform transform = m_data->m_transform;
1793    transform.translate(moved.width(), moved.height());
1794
1795    bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, styleColorSpace, op, destRectIn, origSourceSize);
1796
1797    if (!bmp->hasAlpha())
1798        transparentDC.fillAlphaChannel();
1799}
1800
1801void GraphicsContext::drawIcon(HICON icon, const IntRect& dstRectIn, UINT flags)
1802{
1803    if (!m_data->m_opacity)
1804        return;
1805
1806    ScopeDCProvider dcProvider(m_data);
1807    if (!m_data->m_dc)
1808        return;
1809
1810    IntRect dstRect = m_data->mapRect(dstRectIn);
1811    TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
1812    HDC dc = transparentDC.hdc();
1813    if (!dc)
1814        return;
1815    dstRect.move(transparentDC.toShift());
1816
1817    DrawIconEx(dc, dstRect.x(), dstRect.y(), icon, dstRect.width(), dstRect.height(), 0, NULL, flags);
1818}
1819
1820void GraphicsContext::setPlatformShouldAntialias(bool)
1821{
1822    notImplemented();
1823}
1824
1825void GraphicsContext::setLineDash(const DashArray&, float)
1826{
1827    notImplemented();
1828}
1829
1830void GraphicsContext::clipPath(const Path&, WindRule)
1831{
1832    notImplemented();
1833}
1834
1835} // namespace WebCore
1836