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 38namespace WebCore { 39 40typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops); 41typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops); 42FuncGradientFillRectLinear g_linearGradientFiller = 0; 43FuncGradientFillRectRadial g_radialGradientFiller = 0; 44 45static 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. 51static 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. 61static 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 67class RotationTransform { 68public: 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 } 78 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 } 89 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 } 96 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 112template<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 119template<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 126template<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 153template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform) 154{ 155 return mapRect<T, IntRect, int>(rect, transform); 156} 157 158template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform) 159{ 160 return mapRect<T, FloatRect, double>(rect, transform); 161} 162 163class GraphicsContextPlatformPrivateData { 164public: 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 176enum AlphaPaintType { 177 AlphaPaintNone, 178 AlphaPaintImage, 179 AlphaPaintOther, 180}; 181 182class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData { 183public: 184 GraphicsContextPlatformPrivate(HDC dc) 185 : m_dc(dc) 186 { 187 } 188 ~GraphicsContextPlatformPrivate() 189 { 190 while (!m_backupData.isEmpty()) 191 restore(); 192 } 193 194 IntPoint origin() const 195 { 196 return IntPoint(stableRound(-m_transform.e()), stableRound(-m_transform.f())); 197 } 198 199 void translate(float x, float y) 200 { 201 m_transform.translate(x, y); 202 } 203 204 void scale(const FloatSize& size) 205 { 206 m_transform.scaleNonUniform(size.width(), size.height()); 207 } 208 209 void rotate(float radians) 210 { 211 m_transform.rotate(rad2deg(radians)); 212 } 213 214 void concatCTM(const AffineTransform& transform) 215 { 216 m_transform = transform * m_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::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 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 349static 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 372static inline HGDIOBJ createBrush(const Color& col) 373{ 374 return CreateSolidBrush(RGB(col.red(), col.green(), col.blue())); 375} 376 377template <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 437static 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 446class TransparentLayerDC : Noncopyable { 447public: 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 456private: 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 471TransparentLayerDC::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 538TransparentLayerDC::~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 554void 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 567class ScopeDCProvider : Noncopyable { 568public: 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 } 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 } 582private: 583 GraphicsContextPlatformPrivate* m_data; 584 unsigned m_key1; 585 unsigned m_key2; 586}; 587 588 589GraphicsContext::GraphicsContext(PlatformGraphicsContext* dc) 590: m_common(createGraphicsContextPrivate()) 591, m_data(new GraphicsContextPlatformPrivate(dc)) 592{ 593} 594 595GraphicsContext::~GraphicsContext() 596{ 597 destroyGraphicsContextPrivate(m_common); 598 delete m_data; 599} 600 601void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp) 602{ 603 ASSERT(!m_data->m_dc); 604 m_data->m_bitmap = bmp; 605} 606 607HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) 608{ 609 notImplemented(); 610 ASSERT_NOT_REACHED(); 611 return 0; 612} 613 614void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) 615{ 616 notImplemented(); 617 ASSERT_NOT_REACHED(); 618} 619 620void GraphicsContext::savePlatformState() 621{ 622 m_data->save(); 623} 624 625void GraphicsContext::restorePlatformState() 626{ 627 m_data->restore(); 628} 629 630void 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 683void 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 714void 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 758static inline bool equalAngle(double a, double b) 759{ 760 return fabs(a - b) < 1E-5; 761} 762 763void 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 801void 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 877void 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 950void 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 973void 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 992void 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 1005void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color) 1006{ 1007 // FIXME: implement 1008} 1009 1010void 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 1042void 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 1053void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar) 1054{ 1055 notImplemented(); 1056} 1057 1058void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) 1059{ 1060 notImplemented(); 1061} 1062 1063void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) 1064{ 1065 notImplemented(); 1066} 1067 1068void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) 1069{ 1070 notImplemented(); 1071} 1072 1073void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) 1074{ 1075 notImplemented(); 1076} 1077 1078void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) 1079{ 1080 // We can only clip rectangles on WINCE 1081 clip(rect); 1082} 1083 1084void 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 1098void 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 1135void GraphicsContext::beginTransparencyLayer(float opacity) 1136{ 1137 m_data->save(); 1138 m_data->m_opacity *= opacity; 1139} 1140 1141void GraphicsContext::endTransparencyLayer() 1142{ 1143 m_data->restore(); 1144} 1145 1146void GraphicsContext::concatCTM(const AffineTransform& transform) 1147{ 1148 m_data->concatCTM(transform); 1149} 1150 1151TransformationMatrix& GraphicsContext::affineTransform() 1152{ 1153 return m_data->m_transform; 1154} 1155 1156const TransformationMatrix& GraphicsContext::affineTransform() const 1157{ 1158 return m_data->m_transform; 1159} 1160 1161void GraphicsContext::resetAffineTransform() 1162{ 1163 m_data->m_transform.makeIdentity(); 1164} 1165 1166void GraphicsContext::translate(float x, float y) 1167{ 1168 m_data->translate(x, y); 1169} 1170 1171void GraphicsContext::rotate(float radians) 1172{ 1173 m_data->rotate(radians); 1174} 1175 1176IntPoint GraphicsContext::origin() 1177{ 1178 return m_data->origin(); 1179} 1180 1181void GraphicsContext::scale(const FloatSize& size) 1182{ 1183 m_data->scale(size); 1184} 1185 1186void GraphicsContext::setLineCap(LineCap lineCap) 1187{ 1188 notImplemented(); 1189} 1190 1191void GraphicsContext::setLineJoin(LineJoin lineJoin) 1192{ 1193 notImplemented(); 1194} 1195 1196void GraphicsContext::setMiterLimit(float miter) 1197{ 1198 notImplemented(); 1199} 1200 1201void GraphicsContext::setAlpha(float alpha) 1202{ 1203 m_data->m_opacity = alpha; 1204} 1205 1206void GraphicsContext::setCompositeOperation(CompositeOperator op) 1207{ 1208 notImplemented(); 1209} 1210 1211void GraphicsContext::beginPath() 1212{ 1213 m_data->m_paths.clear(); 1214} 1215 1216void GraphicsContext::addPath(const Path& path) 1217{ 1218 m_data->m_paths.append(path); 1219} 1220 1221void GraphicsContext::clip(const Path& path) 1222{ 1223 notImplemented(); 1224} 1225 1226void GraphicsContext::canvasClip(const Path& path) 1227{ 1228 clip(path); 1229} 1230 1231void GraphicsContext::clipOut(const Path&) 1232{ 1233 notImplemented(); 1234} 1235 1236void GraphicsContext::clipOutEllipseInRect(const IntRect&) 1237{ 1238 notImplemented(); 1239} 1240 1241static 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} 1245void 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 1319void 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 1337FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) 1338{ 1339 notImplemented(); 1340 return frect; 1341} 1342 1343Color 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 1360void 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 1404void 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 1443void 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 1534AffineTransform GraphicsContext::getCTM() const 1535{ 1536 return m_data->m_transform; 1537} 1538 1539void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) 1540{ 1541 notImplemented(); 1542} 1543 1544void 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 1552void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&, ColorSpace) 1553{ 1554 notImplemented(); 1555} 1556 1557void GraphicsContext::clearPlatformShadow() 1558{ 1559 notImplemented(); 1560} 1561 1562void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) 1563{ 1564 notImplemented(); 1565} 1566 1567static inline bool isCharVisible(UChar c) 1568{ 1569 return c && c != zeroWidthSpace; 1570} 1571 1572void 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 1610void 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 1778void 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 1814void 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 1834void 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 1855void 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 1877void 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 1905void 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 1924void GraphicsContext::setPlatformShouldAntialias(bool) 1925{ 1926 notImplemented(); 1927} 1928 1929void GraphicsContext::setLineDash(const DashArray&, float) 1930{ 1931 notImplemented(); 1932} 1933 1934void GraphicsContext::clipPath(WindRule) 1935{ 1936 notImplemented(); 1937} 1938 1939} // namespace WebCore 1940