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