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