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