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