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