1 /* 2 * Copyright (C) 2007-2009 Torch Mobile Inc. 3 * Copyright (C) 2010 Patrick Gansterer <paroga (at) paroga.com> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 * 20 */ 21 22 #include "config.h" 23 #include "GraphicsContext.h" 24 25 #include "AffineTransform.h" 26 #include "Font.h" 27 #include "GDIExtras.h" 28 #include "GlyphBuffer.h" 29 #include "Gradient.h" 30 #include "NotImplemented.h" 31 #include "Path.h" 32 #include "PlatformPathWinCE.h" 33 #include "SharedBitmap.h" 34 #include "SimpleFontData.h" 35 #include <windows.h> 36 #include <wtf/OwnPtr.h> 37 #include <wtf/unicode/CharacterNames.h> 38 39 namespace WebCore { 40 41 typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops); 42 typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops); 43 FuncGradientFillRectLinear g_linearGradientFiller = 0; 44 FuncGradientFillRectRadial g_radialGradientFiller = 0; 45 46 static inline bool isZero(double d) 47 { 48 return d > 0 ? d <= 1.E-10 : d >= -1.E-10; 49 } 50 51 // stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1. 52 static inline int stableRound(double d) 53 { 54 if (d > 0) 55 return static_cast<int>(d + 0.5); 56 57 int i = static_cast<int>(d); 58 return i - d > 0.5 ? i - 1 : i; 59 } 60 61 // Unlike enclosingIntRect(), this function does strict rounding. 62 static inline IntRect roundRect(const FloatRect& r) 63 { 64 return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.maxX()) - stableRound(r.x()), stableRound(r.maxY()) - stableRound(r.y())); 65 } 66 67 // Rotation transformation 68 class RotationTransform { 69 public: 70 RotationTransform() 71 : m_cosA(1.) 72 , m_sinA(0.) 73 , m_preShiftX(0) 74 , m_preShiftY(0) 75 , m_postShiftX(0) 76 , m_postShiftY(0) 77 { 78 } 79 RotationTransform operator-() const 80 { 81 RotationTransform rtn; 82 rtn.m_cosA = m_cosA; 83 rtn.m_sinA = -m_sinA; 84 rtn.m_preShiftX = m_postShiftX; 85 rtn.m_preShiftY = m_postShiftY; 86 rtn.m_postShiftX = m_preShiftX; 87 rtn.m_postShiftY = m_preShiftY; 88 return rtn; 89 } 90 void map(double x1, double y1, double* x2, double* y2) const 91 { 92 x1 += m_preShiftX; 93 y1 += m_preShiftY; 94 *x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX; 95 *y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY; 96 } 97 void map(int x1, int y1, int* x2, int* y2) const 98 { 99 x1 += m_preShiftX; 100 y1 += m_preShiftY; 101 *x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX; 102 *y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY; 103 } 104 105 double m_cosA; 106 double m_sinA; 107 int m_preShiftX; 108 int m_preShiftY; 109 int m_postShiftX; 110 int m_postShiftY; 111 }; 112 113 template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t) 114 { 115 int x, y; 116 t.map(p.x(), p.y(), &x, &y); 117 return IntPoint(x, y); 118 } 119 120 template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t) 121 { 122 double x, y; 123 t.map(p.x(), p.y(), &x, &y); 124 return FloatPoint(static_cast<float>(x), static_cast<float>(y)); 125 } 126 127 template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform) 128 { 129 Value x[4], y[4]; 130 Value l, t, r, b; 131 r = rect.maxX() - 1; 132 b = rect.maxY() - 1; 133 transform.map(rect.x(), rect.y(), x, y); 134 transform.map(rect.x(), b, x + 1, y + 1); 135 transform.map(r, b, x + 2, y + 2); 136 transform.map(r, rect.y(), x + 3, y + 3); 137 l = r = x[3]; 138 t = b = y[3]; 139 for (int i = 0; i < 3; ++i) { 140 if (x[i] < l) 141 l = x[i]; 142 else if (x[i] > r) 143 r = x[i]; 144 145 if (y[i] < t) 146 t = y[i]; 147 else if (y[i] > b) 148 b = y[i]; 149 } 150 151 return IntRect(l, t, r - l + 1, b - t + 1); 152 } 153 154 template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform) 155 { 156 return mapRect<T, IntRect, int>(rect, transform); 157 } 158 159 template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform) 160 { 161 return mapRect<T, FloatRect, double>(rect, transform); 162 } 163 164 class GraphicsContextPlatformPrivateData { 165 public: 166 GraphicsContextPlatformPrivateData() 167 : m_transform() 168 , m_opacity(1.0) 169 { 170 } 171 172 AffineTransform m_transform; 173 float m_opacity; 174 }; 175 176 enum AlphaPaintType { 177 AlphaPaintNone, 178 AlphaPaintImage, 179 AlphaPaintOther, 180 }; 181 182 class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData { 183 public: 184 GraphicsContextPlatformPrivate(HDC dc) 185 : m_dc(dc) 186 { 187 } 188 ~GraphicsContextPlatformPrivate() 189 { 190 while (!m_backupData.isEmpty()) 191 restore(); 192 } 193 194 void translate(float x, float y) 195 { 196 m_transform.translate(x, y); 197 } 198 199 void scale(const FloatSize& size) 200 { 201 m_transform.scaleNonUniform(size.width(), size.height()); 202 } 203 204 void rotate(float radians) 205 { 206 m_transform.rotate(rad2deg(radians)); 207 } 208 209 void concatCTM(const AffineTransform& transform) 210 { 211 m_transform *= transform; 212 } 213 214 void setCTM(const AffineTransform& transform) 215 { 216 m_transform = transform; 217 } 218 219 IntRect mapRect(const IntRect& rect) const 220 { 221 return m_transform.mapRect(rect); 222 } 223 224 FloatRect mapRect(const FloatRect& rect) const 225 { 226 return m_transform.mapRect(rect); 227 } 228 229 IntPoint mapPoint(const IntPoint& point) const 230 { 231 return m_transform.mapPoint(point); 232 } 233 234 FloatPoint mapPoint(const FloatPoint& point) const 235 { 236 return m_transform.mapPoint(point); 237 } 238 239 FloatSize mapSize(const FloatSize& size) const 240 { 241 double w, h; 242 m_transform.map(size.width(), size.height(), w, h); 243 return FloatSize(static_cast<float>(w), static_cast<float>(h)); 244 } 245 246 void save() 247 { 248 if (m_dc) 249 SaveDC(m_dc); 250 251 m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this)); 252 } 253 254 void restore() 255 { 256 if (m_backupData.isEmpty()) 257 return; 258 259 if (m_dc) 260 RestoreDC(m_dc, -1); 261 262 GraphicsContextPlatformPrivateData::operator=(m_backupData.last()); 263 m_backupData.removeLast(); 264 } 265 266 bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); } 267 268 PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const 269 { 270 if (m_opacity <= 0) 271 return 0; 272 273 if (force || m_opacity < 1.) { 274 if (checkClipBox) { 275 RECT clipBox; 276 int clipType = GetClipBox(m_dc, &clipBox); 277 if (clipType == SIMPLEREGION || clipType == COMPLEXREGION) 278 origRect.intersect(clipBox); 279 if (origRect.isEmpty()) 280 return 0; 281 } 282 283 RefPtr<SharedBitmap> bmp = SharedBitmap::create(origRect.size(), alphaPaint == AlphaPaintNone ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, false); 284 SetRect(&bmpRect, 0, 0, origRect.width(), origRect.height()); 285 if (bmp) { 286 switch (alphaPaint) { 287 case AlphaPaintNone: 288 case AlphaPaintImage: 289 { 290 SharedBitmap::DCHolder dc(bmp.get()); 291 if (dc.get()) { 292 BitBlt(dc.get(), 0, 0, origRect.width(), origRect.height(), m_dc, origRect.x(), origRect.y(), SRCCOPY); 293 if (bmp->is32bit() && (!m_bitmap || m_bitmap->is16bit())) { 294 // Set alpha channel 295 unsigned* pixels = (unsigned*)bmp->bytes(); 296 const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels(); 297 while (pixels < pixelsEnd) { 298 *pixels |= 0xFF000000; 299 ++pixels; 300 } 301 } 302 return bmp; 303 } 304 } 305 break; 306 //case AlphaPaintOther: 307 default: 308 memset(bmp->bytes(), 0xFF, bmp->bitmapInfo().numPixels() * 4); 309 return bmp; 310 break; 311 } 312 } 313 } 314 315 bmpRect = origRect; 316 return 0; 317 } 318 319 void paintBackTransparentLayerBitmap(HDC hdc, SharedBitmap* bmp, const IntRect& origRect, AlphaPaintType alphaPaint, const RECT& bmpRect) 320 { 321 if (hdc == m_dc) 322 return; 323 324 if (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) { 325 ASSERT(bmp && bmp->bytes() && bmp->is32bit()); 326 unsigned* pixels = (unsigned*)bmp->bytes(); 327 const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels(); 328 while (pixels < pixelsEnd) { 329 *pixels ^= 0xFF000000; 330 ++pixels; 331 } 332 } 333 if ((m_opacity < 1. || alphaPaint == AlphaPaintOther) && hasAlphaBlendSupport()) { 334 const BLENDFUNCTION blend = { AC_SRC_OVER, 0 335 , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255) 336 , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA }; 337 bool success = alphaBlendIfSupported(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend); 338 ASSERT_UNUSED(success, success); 339 } else 340 StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY); 341 } 342 343 HDC m_dc; 344 RefPtr<SharedBitmap> m_bitmap; 345 Vector<GraphicsContextPlatformPrivateData> m_backupData; 346 }; 347 348 static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style) 349 { 350 int width = stableRound(fWidth); 351 if (width < 1) 352 width = 1; 353 354 int penStyle = PS_NULL; 355 switch (style) { 356 case SolidStroke: 357 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 371 static inline PassOwnPtr<HBRUSH> createBrush(const Color& col) 372 { 373 return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue()))); 374 } 375 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 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 451 HDC hdc() const { return m_memDc; } 452 const RECT& rect() const { return m_bmpRect; } 453 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 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 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 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: 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 } 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 588 void GraphicsContext::platformInit(PlatformGraphicsContext* dc) 589 { 590 m_data = new GraphicsContextPlatformPrivate(dc); 591 } 592 593 void GraphicsContext::platformDestroy() 594 { 595 delete m_data; 596 } 597 598 void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp) 599 { 600 ASSERT(!m_data->m_dc); 601 m_data->m_bitmap = bmp; 602 } 603 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 611 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) 612 { 613 } 614 615 void GraphicsContext::savePlatformState() 616 { 617 m_data->save(); 618 } 619 620 void GraphicsContext::restorePlatformState() 621 { 622 m_data->restore(); 623 } 624 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 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 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 739 static inline bool equalAngle(double a, double b) 740 { 741 return fabs(a - b) < 1E-5; 742 } 743 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 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 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 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 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 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 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 987 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) 988 { 989 // FIXME: implement 990 } 991 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 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 1035 void GraphicsContext::drawLineForTextChecking(const FloatPoint&, float width, TextCheckingLineStyle style) 1036 { 1037 notImplemented(); 1038 } 1039 1040 void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) 1041 { 1042 notImplemented(); 1043 } 1044 1045 void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) 1046 { 1047 notImplemented(); 1048 } 1049 1050 void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) 1051 { 1052 notImplemented(); 1053 } 1054 1055 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) 1056 { 1057 notImplemented(); 1058 } 1059 1060 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) 1061 { 1062 // We can only clip rectangles on WINCE 1063 clip(rect); 1064 } 1065 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 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 1116 void GraphicsContext::beginTransparencyLayer(float opacity) 1117 { 1118 m_data->save(); 1119 m_data->m_opacity *= opacity; 1120 } 1121 1122 void GraphicsContext::endTransparencyLayer() 1123 { 1124 m_data->restore(); 1125 } 1126 1127 void GraphicsContext::concatCTM(const AffineTransform& transform) 1128 { 1129 m_data->concatCTM(transform); 1130 } 1131 1132 void GraphicsContext::setCTM(const AffineTransform& transform) 1133 { 1134 m_data->setCTM(transform); 1135 } 1136 1137 AffineTransform& GraphicsContext::affineTransform() 1138 { 1139 return m_data->m_transform; 1140 } 1141 1142 const AffineTransform& GraphicsContext::affineTransform() const 1143 { 1144 return m_data->m_transform; 1145 } 1146 1147 void GraphicsContext::resetAffineTransform() 1148 { 1149 m_data->m_transform.makeIdentity(); 1150 } 1151 1152 void GraphicsContext::translate(float x, float y) 1153 { 1154 m_data->translate(x, y); 1155 } 1156 1157 void GraphicsContext::rotate(float radians) 1158 { 1159 m_data->rotate(radians); 1160 } 1161 1162 void GraphicsContext::scale(const FloatSize& size) 1163 { 1164 m_data->scale(size); 1165 } 1166 1167 void GraphicsContext::setLineCap(LineCap lineCap) 1168 { 1169 notImplemented(); 1170 } 1171 1172 void GraphicsContext::setLineJoin(LineJoin lineJoin) 1173 { 1174 notImplemented(); 1175 } 1176 1177 void GraphicsContext::setMiterLimit(float miter) 1178 { 1179 notImplemented(); 1180 } 1181 1182 void GraphicsContext::setAlpha(float alpha) 1183 { 1184 m_data->m_opacity = alpha; 1185 } 1186 1187 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) 1188 { 1189 notImplemented(); 1190 } 1191 1192 void GraphicsContext::clip(const Path& path) 1193 { 1194 notImplemented(); 1195 } 1196 1197 void GraphicsContext::canvasClip(const Path& path) 1198 { 1199 clip(path); 1200 } 1201 1202 void GraphicsContext::clipOut(const Path&) 1203 { 1204 notImplemented(); 1205 } 1206 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 } 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 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 1303 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) 1304 { 1305 notImplemented(); 1306 return frect; 1307 } 1308 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 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 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 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 1490 AffineTransform GraphicsContext::getCTM() const 1491 { 1492 return m_data->m_transform; 1493 } 1494 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 1507 void GraphicsContext::setPlatformShadow(const FloatSize&, float, const Color&, ColorSpace) 1508 { 1509 notImplemented(); 1510 } 1511 1512 void GraphicsContext::clearPlatformShadow() 1513 { 1514 notImplemented(); 1515 } 1516 1517 InterpolationQuality GraphicsContext::imageInterpolationQuality() const 1518 { 1519 notImplemented(); 1520 return InterpolationDefault; 1521 } 1522 1523 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) 1524 { 1525 notImplemented(); 1526 } 1527 1528 static inline bool isCharVisible(UChar c) 1529 { 1530 return c && c != zeroWidthSpace; 1531 } 1532 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 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 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 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 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 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 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 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 1886 void GraphicsContext::setPlatformShouldAntialias(bool) 1887 { 1888 notImplemented(); 1889 } 1890 1891 void GraphicsContext::setLineDash(const DashArray&, float) 1892 { 1893 notImplemented(); 1894 } 1895 1896 void GraphicsContext::clipPath(const Path&, WindRule) 1897 { 1898 notImplemented(); 1899 } 1900 1901 } // namespace WebCore 1902