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