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