• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
isZero(double d)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.
stableRound(double d)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.
roundRect(const FloatRect & r)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:
RotationTransform()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     }
operator -() const78     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     }
map(double x1,double y1,double * x2,double * y2) const89     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     }
map(int x1,int y1,int * x2,int * y2) const96     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 
mapPoint(const IntPoint & p,const T & t)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 
mapPoint(const FloatPoint & p,const T & t)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 
mapRect(const Rect & rect,const Transform & transform)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 
mapRect(const IntRect & rect,const T & transform)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 
mapRect(const FloatRect & rect,const T & transform)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:
GraphicsContextPlatformPrivateData()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:
GraphicsContextPlatformPrivate(HDC dc)184     GraphicsContextPlatformPrivate(HDC dc)
185         : m_dc(dc)
186     {
187     }
~GraphicsContextPlatformPrivate()188     ~GraphicsContextPlatformPrivate()
189     {
190         while (!m_backupData.isEmpty())
191             restore();
192     }
193 
origin() const194     IntPoint origin() const
195     {
196         return IntPoint(stableRound(-m_transform.e()), stableRound(-m_transform.f()));
197     }
198 
translate(float x,float y)199     void translate(float x, float y)
200     {
201         m_transform.translate(x, y);
202     }
203 
scale(const FloatSize & size)204     void scale(const FloatSize& size)
205     {
206         m_transform.scaleNonUniform(size.width(), size.height());
207     }
208 
rotate(float radians)209     void rotate(float radians)
210     {
211         m_transform.rotate(rad2deg(radians));
212     }
213 
concatCTM(const AffineTransform & transform)214     void  concatCTM(const AffineTransform& transform)
215     {
216         m_transform = transform * m_transform;
217     }
218 
mapRect(const IntRect & rect) const219     IntRect mapRect(const IntRect& rect) const
220     {
221         return m_transform.mapRect(rect);
222     }
223 
mapRect(const FloatRect & rect) const224     FloatRect mapRect(const FloatRect& rect) const
225     {
226         return m_transform.mapRect(rect);
227     }
228 
mapPoint(const IntPoint & point) const229     IntPoint mapPoint(const IntPoint& point) const
230     {
231         return m_transform.mapPoint(point);
232     }
233 
mapPoint(const FloatPoint & point) const234     FloatPoint mapPoint(const FloatPoint& point) const
235     {
236         return m_transform.mapPoint(point);
237     }
238 
mapSize(const FloatSize & size) const239     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 
save()246     void save()
247     {
248         if (m_dc)
249             SaveDC(m_dc);
250 
251         m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this));
252     }
253 
restore()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 
hasAlpha() const266     bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); }
267 
getTransparentLayerBitmap(IntRect & origRect,AlphaPaintType alphaPaint,RECT & bmpRect,bool checkClipBox,bool force) const268     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 
paintBackTransparentLayerBitmap(HDC hdc,SharedBitmap * bmp,const IntRect & origRect,AlphaPaintType alphaPaint,const RECT & bmpRect)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 
createPen(const Color & col,double fWidth,StrokeStyle style)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 
createBrush(const Color & col)372 static inline HGDIOBJ createBrush(const Color& col)
373 {
374     return CreateSolidBrush(RGB(col.red(), col.green(), col.blue()));
375 }
376 
_rotateBitmap(SharedBitmap * destBmp,const SharedBitmap * sourceBmp,const RotationTransform & transform)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 
rotateBitmap(SharedBitmap * destBmp,const SharedBitmap * sourceBmp,const RotationTransform & transform)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 
hdc() const451     HDC hdc() const { return m_memDc; }
rect() const452     const RECT& rect() const { return m_bmpRect; }
toShift() const453     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 
TransparentLayerDC(GraphicsContextPlatformPrivate * data,IntRect & origRect,const IntRect * rectBeforeTransform,int alpha,bool paintImage)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 
~TransparentLayerDC()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 
fillAlphaChannel()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:
ScopeDCProvider(GraphicsContextPlatformPrivate * data)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     }
~ScopeDCProvider()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 
GraphicsContext(PlatformGraphicsContext * dc)589 GraphicsContext::GraphicsContext(PlatformGraphicsContext* dc)
590 : m_common(createGraphicsContextPrivate())
591 , m_data(new GraphicsContextPlatformPrivate(dc))
592 {
593 }
594 
~GraphicsContext()595 GraphicsContext::~GraphicsContext()
596 {
597     destroyGraphicsContextPrivate(m_common);
598     delete m_data;
599 }
600 
setBitmap(PassRefPtr<SharedBitmap> bmp)601 void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp)
602 {
603     ASSERT(!m_data->m_dc);
604     m_data->m_bitmap = bmp;
605 }
606 
getWindowsContext(const IntRect & dstRect,bool supportAlphaBlend,bool mayCreateBitmap)607 HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
608 {
609     notImplemented();
610     ASSERT_NOT_REACHED();
611     return 0;
612 }
613 
releaseWindowsContext(HDC hdc,const IntRect & dstRect,bool supportAlphaBlend,bool mayCreateBitmap)614 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
615 {
616     notImplemented();
617     ASSERT_NOT_REACHED();
618 }
619 
savePlatformState()620 void GraphicsContext::savePlatformState()
621 {
622     m_data->save();
623 }
624 
restorePlatformState()625 void GraphicsContext::restorePlatformState()
626 {
627     m_data->restore();
628 }
629 
drawRect(const IntRect & rect)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 
drawLine(const IntPoint & point1,const IntPoint & point2)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 
drawEllipse(const IntRect & rect)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 
equalAngle(double a,double b)758 static inline bool equalAngle(double a, double b)
759 {
760     return fabs(a - b) < 1E-5;
761 }
762 
getEllipsePointByAngle(double angle,double a,double b,float & x,float & y)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 
strokeArc(const IntRect & rect,int startAngle,int angleSpan)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 
drawConvexPolygon(size_t npoints,const FloatPoint * points,bool shouldAntialias)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 
fillRect(const FloatRect & rect,const Color & color,ColorSpace colorSpace)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 
clip(const FloatRect & rect)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 
clipOut(const IntRect & rect)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 
drawFocusRing(const Vector<Path> & paths,int width,int offset,const Color & color)1005 void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
1006 {
1007     // FIXME: implement
1008 }
1009 
drawFocusRing(const Vector<IntRect> & rects,int width,int offset,const Color & color)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 
drawLineForText(const IntPoint & origin,int width,bool printing)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 
drawLineForMisspellingOrBadGrammar(const IntPoint &,int width,bool grammar)1053 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar)
1054 {
1055     notImplemented();
1056 }
1057 
setPlatformFillColor(const Color & col,ColorSpace colorSpace)1058 void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
1059 {
1060     notImplemented();
1061 }
1062 
setPlatformStrokeColor(const Color & col,ColorSpace colorSpace)1063 void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
1064 {
1065     notImplemented();
1066 }
1067 
setPlatformStrokeThickness(float strokeThickness)1068 void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
1069 {
1070     notImplemented();
1071 }
1072 
setURLForRect(const KURL & link,const IntRect & destRect)1073 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
1074 {
1075     notImplemented();
1076 }
1077 
addInnerRoundedRectClip(const IntRect & rect,int thickness)1078 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
1079 {
1080     // We can only clip rectangles on WINCE
1081     clip(rect);
1082 }
1083 
clearRect(const FloatRect & rect)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 
strokeRect(const FloatRect & rect,float width)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 
beginTransparencyLayer(float opacity)1135 void GraphicsContext::beginTransparencyLayer(float opacity)
1136 {
1137     m_data->save();
1138     m_data->m_opacity *= opacity;
1139 }
1140 
endTransparencyLayer()1141 void GraphicsContext::endTransparencyLayer()
1142 {
1143     m_data->restore();
1144 }
1145 
concatCTM(const AffineTransform & transform)1146 void GraphicsContext::concatCTM(const AffineTransform& transform)
1147 {
1148     m_data->concatCTM(transform);
1149 }
1150 
affineTransform()1151 TransformationMatrix& GraphicsContext::affineTransform()
1152 {
1153     return m_data->m_transform;
1154 }
1155 
affineTransform() const1156 const TransformationMatrix& GraphicsContext::affineTransform() const
1157 {
1158     return m_data->m_transform;
1159 }
1160 
resetAffineTransform()1161 void GraphicsContext::resetAffineTransform()
1162 {
1163     m_data->m_transform.makeIdentity();
1164 }
1165 
translate(float x,float y)1166 void GraphicsContext::translate(float x, float y)
1167 {
1168     m_data->translate(x, y);
1169 }
1170 
rotate(float radians)1171 void GraphicsContext::rotate(float radians)
1172 {
1173     m_data->rotate(radians);
1174 }
1175 
origin()1176 IntPoint GraphicsContext::origin()
1177 {
1178     return m_data->origin();
1179 }
1180 
scale(const FloatSize & size)1181 void GraphicsContext::scale(const FloatSize& size)
1182 {
1183     m_data->scale(size);
1184 }
1185 
setLineCap(LineCap lineCap)1186 void GraphicsContext::setLineCap(LineCap lineCap)
1187 {
1188     notImplemented();
1189 }
1190 
setLineJoin(LineJoin lineJoin)1191 void GraphicsContext::setLineJoin(LineJoin lineJoin)
1192 {
1193     notImplemented();
1194 }
1195 
setMiterLimit(float miter)1196 void GraphicsContext::setMiterLimit(float miter)
1197 {
1198     notImplemented();
1199 }
1200 
setAlpha(float alpha)1201 void GraphicsContext::setAlpha(float alpha)
1202 {
1203     m_data->m_opacity = alpha;
1204 }
1205 
setCompositeOperation(CompositeOperator op)1206 void GraphicsContext::setCompositeOperation(CompositeOperator op)
1207 {
1208     notImplemented();
1209 }
1210 
beginPath()1211 void GraphicsContext::beginPath()
1212 {
1213     m_data->m_paths.clear();
1214 }
1215 
addPath(const Path & path)1216 void GraphicsContext::addPath(const Path& path)
1217 {
1218     m_data->m_paths.append(path);
1219 }
1220 
clip(const Path & path)1221 void GraphicsContext::clip(const Path& path)
1222 {
1223     notImplemented();
1224 }
1225 
canvasClip(const Path & path)1226 void GraphicsContext::canvasClip(const Path& path)
1227 {
1228     clip(path);
1229 }
1230 
clipOut(const Path &)1231 void GraphicsContext::clipOut(const Path&)
1232 {
1233     notImplemented();
1234 }
1235 
clipOutEllipseInRect(const IntRect &)1236 void GraphicsContext::clipOutEllipseInRect(const IntRect&)
1237 {
1238     notImplemented();
1239 }
1240 
rectCenterPoint(const RECT & rect)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 }
fillRoundedRect(const IntRect & fillRect,const IntSize & topLeft,const IntSize & topRight,const IntSize & bottomLeft,const IntSize & bottomRight,const Color & c,ColorSpace colorSpace)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 
drawRoundCorner(bool needsNewClip,RECT clipRect,RECT rectWin,HDC dc,int width,int height)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 
roundToDevicePixels(const FloatRect & frect)1337 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
1338 {
1339     notImplemented();
1340     return frect;
1341 }
1342 
gradientAverageColor(const Gradient * gradient)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 
fillPath()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 
strokePath()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 
fillRect(const FloatRect & r,const Gradient * gradient)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 
getCTM() const1534 AffineTransform GraphicsContext::getCTM() const
1535 {
1536     return m_data->m_transform;
1537 }
1538 
clipToImageBuffer(const FloatRect &,const ImageBuffer *)1539 void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
1540 {
1541     notImplemented();
1542 }
1543 
fillRect(const FloatRect & rect)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 
setPlatformShadow(const IntSize &,int,const Color &,ColorSpace)1552 void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&, ColorSpace)
1553 {
1554     notImplemented();
1555 }
1556 
clearPlatformShadow()1557 void GraphicsContext::clearPlatformShadow()
1558 {
1559     notImplemented();
1560 }
1561 
setImageInterpolationQuality(InterpolationQuality)1562 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
1563 {
1564     notImplemented();
1565 }
1566 
isCharVisible(UChar c)1567 static inline bool isCharVisible(UChar c)
1568 {
1569     return c && c != zeroWidthSpace;
1570 }
1571 
drawText(const Font & font,const TextRun & run,const IntPoint & point,int from,int to)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 
drawText(const SimpleFontData * fontData,const GlyphBuffer & glyphBuffer,int from,int numGlyphs,const FloatPoint & point)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 
drawFrameControl(const IntRect & rect,unsigned type,unsigned state)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 
drawFocusRect(const IntRect & rect)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 
paintTextField(const IntRect & rect,unsigned state)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 
drawBitmap(SharedBitmap * bmp,const IntRect & dstRectIn,const IntRect & srcRect,CompositeOperator compositeOp)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 
drawBitmapPattern(SharedBitmap * bmp,const FloatRect & tileRectIn,const AffineTransform & patternTransform,const FloatPoint & phase,CompositeOperator op,const FloatRect & destRectIn,const IntSize & origSourceSize)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 
drawIcon(HICON icon,const IntRect & dstRectIn,UINT flags)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 
setPlatformShouldAntialias(bool)1924 void GraphicsContext::setPlatformShouldAntialias(bool)
1925 {
1926     notImplemented();
1927 }
1928 
setLineDash(const DashArray &,float)1929 void GraphicsContext::setLineDash(const DashArray&, float)
1930 {
1931     notImplemented();
1932 }
1933 
clipPath(WindRule)1934 void GraphicsContext::clipPath(WindRule)
1935 {
1936     notImplemented();
1937 }
1938 
1939 } // namespace WebCore
1940