1/* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "GraphicsContext.h" 28 29#include "BidiResolver.h" 30#include "BitmapImage.h" 31#include "Gradient.h" 32#include "ImageBuffer.h" 33#include "IntRect.h" 34#include "RoundedRect.h" 35#include "TextRun.h" 36 37#include "stdio.h" 38 39using namespace std; 40 41namespace WebCore { 42 43class TextRunIterator { 44public: 45 TextRunIterator() 46 : m_textRun(0) 47 , m_offset(0) 48 { 49 } 50 51 TextRunIterator(const TextRun* textRun, unsigned offset) 52 : m_textRun(textRun) 53 , m_offset(offset) 54 { 55 } 56 57 TextRunIterator(const TextRunIterator& other) 58 : m_textRun(other.m_textRun) 59 , m_offset(other.m_offset) 60 { 61 } 62 63 unsigned offset() const { return m_offset; } 64 void increment() { m_offset++; } 65 bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); } 66 UChar current() const { return (*m_textRun)[m_offset]; } 67 WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); } 68 69 bool operator==(const TextRunIterator& other) 70 { 71 return m_offset == other.m_offset && m_textRun == other.m_textRun; 72 } 73 74 bool operator!=(const TextRunIterator& other) { return !operator==(other); } 75 76private: 77 const TextRun* m_textRun; 78 int m_offset; 79}; 80 81GraphicsContext::GraphicsContext(PlatformGraphicsContext* platformGraphicsContext) 82 : m_updatingControlTints(false) 83 , m_transparencyCount(0) 84{ 85 platformInit(platformGraphicsContext); 86} 87 88GraphicsContext::~GraphicsContext() 89{ 90 ASSERT(m_stack.isEmpty()); 91 ASSERT(!m_transparencyCount); 92 platformDestroy(); 93} 94 95void GraphicsContext::save() 96{ 97 if (paintingDisabled()) 98 return; 99 100 m_stack.append(m_state); 101 102 savePlatformState(); 103} 104 105void GraphicsContext::restore() 106{ 107 if (paintingDisabled()) 108 return; 109 110 if (m_stack.isEmpty()) { 111 LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); 112 return; 113 } 114 m_state = m_stack.last(); 115 m_stack.removeLast(); 116 117 restorePlatformState(); 118} 119 120void GraphicsContext::setStrokeThickness(float thickness) 121{ 122 m_state.strokeThickness = thickness; 123 setPlatformStrokeThickness(thickness); 124} 125 126void GraphicsContext::setStrokeStyle(StrokeStyle style) 127{ 128 m_state.strokeStyle = style; 129 setPlatformStrokeStyle(style); 130} 131 132void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace) 133{ 134 m_state.strokeColor = color; 135 m_state.strokeColorSpace = colorSpace; 136 m_state.strokeGradient.clear(); 137 m_state.strokePattern.clear(); 138 setPlatformStrokeColor(color, colorSpace); 139} 140 141void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace) 142{ 143 m_state.shadowOffset = offset; 144 m_state.shadowBlur = blur; 145 m_state.shadowColor = color; 146 m_state.shadowColorSpace = colorSpace; 147 setPlatformShadow(offset, blur, color, colorSpace); 148} 149 150void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace) 151{ 152 m_state.shadowOffset = offset; 153 m_state.shadowBlur = blur; 154 m_state.shadowColor = color; 155 m_state.shadowColorSpace = colorSpace; 156#if USE(CG) 157 m_state.shadowsUseLegacyRadius = true; 158#endif 159 setPlatformShadow(offset, blur, color, colorSpace); 160} 161 162void GraphicsContext::clearShadow() 163{ 164 m_state.shadowOffset = FloatSize(); 165 m_state.shadowBlur = 0; 166 m_state.shadowColor = Color(); 167 m_state.shadowColorSpace = ColorSpaceDeviceRGB; 168 clearPlatformShadow(); 169} 170 171bool GraphicsContext::hasShadow() const 172{ 173 return m_state.shadowColor.isValid() && m_state.shadowColor.alpha() 174 && (m_state.shadowBlur || m_state.shadowOffset.width() || m_state.shadowOffset.height()); 175} 176 177bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color, ColorSpace& colorSpace) const 178{ 179 offset = m_state.shadowOffset; 180 blur = m_state.shadowBlur; 181 color = m_state.shadowColor; 182 colorSpace = m_state.shadowColorSpace; 183 184 return hasShadow(); 185} 186 187bool GraphicsContext::hasBlurredShadow() const 188{ 189 return m_state.shadowColor.isValid() && m_state.shadowColor.alpha() && m_state.shadowBlur; 190} 191 192#if PLATFORM(QT) || USE(CAIRO) 193bool GraphicsContext::mustUseShadowBlur() const 194{ 195 // We can't avoid ShadowBlur if the shadow has blur. 196 if (hasBlurredShadow()) 197 return true; 198 // We can avoid ShadowBlur and optimize, since we're not drawing on a 199 // canvas and box shadows are affected by the transformation matrix. 200 if (!m_state.shadowsIgnoreTransforms) 201 return false; 202 // We can avoid ShadowBlur, since there are no transformations to apply to the canvas. 203 if (getCTM().isIdentity()) 204 return false; 205 // Otherwise, no chance avoiding ShadowBlur. 206 return true; 207} 208#endif 209 210float GraphicsContext::strokeThickness() const 211{ 212 return m_state.strokeThickness; 213} 214 215StrokeStyle GraphicsContext::strokeStyle() const 216{ 217 return m_state.strokeStyle; 218} 219 220Color GraphicsContext::strokeColor() const 221{ 222 return m_state.strokeColor; 223} 224 225ColorSpace GraphicsContext::strokeColorSpace() const 226{ 227 return m_state.strokeColorSpace; 228} 229 230WindRule GraphicsContext::fillRule() const 231{ 232 return m_state.fillRule; 233} 234 235void GraphicsContext::setFillRule(WindRule fillRule) 236{ 237 m_state.fillRule = fillRule; 238} 239 240void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace) 241{ 242 m_state.fillColor = color; 243 m_state.fillColorSpace = colorSpace; 244 m_state.fillGradient.clear(); 245 m_state.fillPattern.clear(); 246 setPlatformFillColor(color, colorSpace); 247} 248 249Color GraphicsContext::fillColor() const 250{ 251 return m_state.fillColor; 252} 253 254ColorSpace GraphicsContext::fillColorSpace() const 255{ 256 return m_state.fillColorSpace; 257} 258 259void GraphicsContext::setShouldAntialias(bool b) 260{ 261 m_state.shouldAntialias = b; 262 setPlatformShouldAntialias(b); 263} 264 265bool GraphicsContext::shouldAntialias() const 266{ 267 return m_state.shouldAntialias; 268} 269 270void GraphicsContext::setShouldSmoothFonts(bool b) 271{ 272 m_state.shouldSmoothFonts = b; 273 setPlatformShouldSmoothFonts(b); 274} 275 276bool GraphicsContext::shouldSmoothFonts() const 277{ 278 return m_state.shouldSmoothFonts; 279} 280 281void GraphicsContext::setShouldSubpixelQuantizeFonts(bool b) 282{ 283 m_state.shouldSubpixelQuantizeFonts = b; 284} 285 286bool GraphicsContext::shouldSubpixelQuantizeFonts() const 287{ 288 return m_state.shouldSubpixelQuantizeFonts; 289} 290 291const GraphicsContextState& GraphicsContext::state() const 292{ 293 return m_state; 294} 295 296void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) 297{ 298 ASSERT(pattern); 299 if (!pattern) { 300 setStrokeColor(Color::black, ColorSpaceDeviceRGB); 301 return; 302 } 303 m_state.strokeGradient.clear(); 304 m_state.strokePattern = pattern; 305} 306 307void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) 308{ 309 ASSERT(pattern); 310 if (!pattern) { 311 setFillColor(Color::black, ColorSpaceDeviceRGB); 312 return; 313 } 314 m_state.fillGradient.clear(); 315 m_state.fillPattern = pattern; 316} 317 318void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) 319{ 320 ASSERT(gradient); 321 if (!gradient) { 322 setStrokeColor(Color::black, ColorSpaceDeviceRGB); 323 return; 324 } 325 m_state.strokeGradient = gradient; 326 m_state.strokePattern.clear(); 327} 328 329void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) 330{ 331 ASSERT(gradient); 332 if (!gradient) { 333 setFillColor(Color::black, ColorSpaceDeviceRGB); 334 return; 335 } 336 m_state.fillGradient = gradient; 337 m_state.fillPattern.clear(); 338} 339 340Gradient* GraphicsContext::fillGradient() const 341{ 342 return m_state.fillGradient.get(); 343} 344 345Gradient* GraphicsContext::strokeGradient() const 346{ 347 return m_state.strokeGradient.get(); 348} 349 350Pattern* GraphicsContext::fillPattern() const 351{ 352 return m_state.fillPattern.get(); 353} 354 355Pattern* GraphicsContext::strokePattern() const 356{ 357 return m_state.strokePattern.get(); 358} 359 360void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms) 361{ 362 m_state.shadowsIgnoreTransforms = ignoreTransforms; 363} 364 365bool GraphicsContext::shadowsIgnoreTransforms() const 366{ 367 return m_state.shadowsIgnoreTransforms; 368} 369 370void GraphicsContext::beginTransparencyLayer(float opacity) 371{ 372 beginPlatformTransparencyLayer(opacity); 373 ++m_transparencyCount; 374} 375 376void GraphicsContext::endTransparencyLayer() 377{ 378 endPlatformTransparencyLayer(); 379 ASSERT(m_transparencyCount > 0); 380 --m_transparencyCount; 381} 382 383#if !PLATFORM(QT) 384bool GraphicsContext::isInTransparencyLayer() const 385{ 386 return (m_transparencyCount > 0) && supportsTransparencyLayers(); 387} 388#endif 389 390bool GraphicsContext::updatingControlTints() const 391{ 392 return m_updatingControlTints; 393} 394 395void GraphicsContext::setUpdatingControlTints(bool b) 396{ 397 setPaintingDisabled(b); 398 m_updatingControlTints = b; 399} 400 401void GraphicsContext::setPaintingDisabled(bool f) 402{ 403 m_state.paintingDisabled = f; 404} 405 406bool GraphicsContext::paintingDisabled() const 407{ 408 return m_state.paintingDisabled; 409} 410 411#if !USE(WINGDI) 412void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to) 413{ 414 if (paintingDisabled()) 415 return; 416 417 font.drawText(this, run, point, from, to); 418} 419#endif 420 421void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) 422{ 423 if (paintingDisabled()) 424 return; 425 426 font.drawEmphasisMarks(this, run, mark, point, from, to); 427} 428 429void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction) 430{ 431 if (paintingDisabled()) 432 return; 433 434 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; 435 bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride())); 436 bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0)); 437 438 // FIXME: This ownership should be reversed. We should pass BidiRunList 439 // to BidiResolver in createBidiRunsForLine. 440 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); 441 bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); 442 if (!bidiRuns.runCount()) 443 return; 444 445 FloatPoint currPoint = point; 446 BidiCharacterRun* bidiRun = bidiRuns.firstRun(); 447 while (bidiRun) { 448 TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start()); 449 bool isRTL = bidiRun->level() % 2; 450 subrun.setDirection(isRTL ? RTL : LTR); 451 subrun.setDirectionalOverride(bidiRun->dirOverride(false)); 452 453 font.drawText(this, subrun, currPoint, 0, -1, customFontNotReadyAction); 454 455 bidiRun = bidiRun->next(); 456 // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. 457 if (bidiRun) 458 currPoint.move(font.width(subrun), 0); 459 } 460 461 bidiRuns.deleteRuns(); 462} 463 464void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) 465{ 466 if (paintingDisabled()) 467 return; 468 469 fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace); 470} 471 472void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) 473{ 474 if (!image) 475 return; 476 drawImage(image, styleColorSpace, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation); 477} 478 479void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) 480{ 481 if (!image) 482 return; 483 drawImage(image, styleColorSpace, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation, useLowQualityScale); 484} 485 486void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) 487{ 488 drawImage(image, styleColorSpace, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, shouldRespectImageOrientation); 489} 490 491void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) 492{ 493 drawImage(image, styleColorSpace, dest, src, op, BlendModeNormal, shouldRespectImageOrientation, useLowQualityScale); 494} 495 496void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest) 497{ 498 if (!image) 499 return; 500 drawImage(image, styleColorSpace, dest, FloatRect(IntRect(IntPoint(), image->size()))); 501} 502 503void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) 504{ if (paintingDisabled() || !image) 505 return; 506 507 InterpolationQuality previousInterpolationQuality = InterpolationDefault; 508 509 if (useLowQualityScale) { 510 previousInterpolationQuality = imageInterpolationQuality(); 511 // FIXME (49002): Should be InterpolationLow 512 setImageInterpolationQuality(InterpolationNone); 513 } 514 515 image->draw(this, dest, src, styleColorSpace, op, blendMode, shouldRespectImageOrientation); 516 517 if (useLowQualityScale) 518 setImageInterpolationQuality(previousInterpolationQuality); 519} 520 521void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale, BlendMode blendMode) 522{ 523 if (paintingDisabled() || !image) 524 return; 525 526 if (useLowQualityScale) { 527 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 528 setImageInterpolationQuality(InterpolationLow); 529 image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op, blendMode); 530 setImageInterpolationQuality(previousInterpolationQuality); 531 } else 532 image->drawTiled(this, destRect, srcPoint, tileSize, styleColorSpace, op, blendMode); 533} 534 535void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, 536 const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale) 537{ 538 if (paintingDisabled() || !image) 539 return; 540 541 if (hRule == Image::StretchTile && vRule == Image::StretchTile) { 542 // Just do a scale. 543 drawImage(image, styleColorSpace, dest, srcRect, op); 544 return; 545 } 546 547 if (useLowQualityScale) { 548 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 549 setImageInterpolationQuality(InterpolationLow); 550 image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op); 551 setImageInterpolationQuality(previousInterpolationQuality); 552 } else 553 image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, styleColorSpace, op); 554} 555 556void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op, BlendMode blendMode) 557{ 558 if (!image) 559 return; 560 drawImageBuffer(image, styleColorSpace, FloatRect(IntRect(p, image->logicalSize())), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode); 561} 562 563void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 564{ 565 if (!image) 566 return; 567 drawImageBuffer(image, styleColorSpace, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode, useLowQualityScale); 568} 569 570void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode) 571{ 572 drawImageBuffer(image, styleColorSpace, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, blendMode); 573} 574 575void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 576{ 577 drawImageBuffer(image, styleColorSpace, FloatRect(dest), FloatRect(srcRect), op, blendMode, useLowQualityScale); 578} 579 580void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest) 581{ 582 if (!image) 583 return; 584 drawImageBuffer(image, styleColorSpace, dest, FloatRect(IntRect(IntPoint(), image->logicalSize()))); 585} 586 587void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 588{ 589 if (paintingDisabled() || !image) 590 return; 591 592 if (useLowQualityScale) { 593 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 594 // FIXME (49002): Should be InterpolationLow 595 setImageInterpolationQuality(InterpolationNone); 596 image->draw(this, styleColorSpace, dest, src, op, blendMode, useLowQualityScale); 597 setImageInterpolationQuality(previousInterpolationQuality); 598 } else 599 image->draw(this, styleColorSpace, dest, src, op, blendMode, useLowQualityScale); 600} 601 602#if !PLATFORM(QT) 603void GraphicsContext::clip(const IntRect& rect) 604{ 605 clip(FloatRect(rect)); 606} 607#endif 608 609void GraphicsContext::clipRoundedRect(const RoundedRect& rect) 610{ 611 if (paintingDisabled()) 612 return; 613 614 if (!rect.isRounded()) { 615 clip(rect.rect()); 616 return; 617 } 618 619 Path path; 620 path.addRoundedRect(rect); 621 clip(path); 622} 623 624void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect) 625{ 626 if (paintingDisabled()) 627 return; 628 629 if (!rect.isRounded()) { 630 clipOut(rect.rect()); 631 return; 632 } 633 634 Path path; 635 path.addRoundedRect(rect); 636 clipOut(path); 637} 638 639void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect) 640{ 641 if (paintingDisabled()) 642 return; 643 buffer->clip(this, rect); 644} 645 646#if !USE(CG) && !PLATFORM(QT) && !USE(CAIRO) 647IntRect GraphicsContext::clipBounds() const 648{ 649 ASSERT_NOT_REACHED(); 650 return IntRect(); 651} 652#endif 653 654TextDrawingModeFlags GraphicsContext::textDrawingMode() const 655{ 656 return m_state.textDrawingMode; 657} 658 659void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode) 660{ 661 m_state.textDrawingMode = mode; 662 if (paintingDisabled()) 663 return; 664 setPlatformTextDrawingMode(mode); 665} 666 667void GraphicsContext::fillRect(const FloatRect& rect, Gradient& gradient) 668{ 669 if (paintingDisabled()) 670 return; 671 gradient.fill(this, rect); 672} 673 674void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op, BlendMode blendMode) 675{ 676 if (paintingDisabled()) 677 return; 678 679 CompositeOperator previousOperator = compositeOperation(); 680 setCompositeOperation(op, blendMode); 681 fillRect(rect, color, styleColorSpace); 682 setCompositeOperation(previousOperator); 683} 684 685void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color, ColorSpace colorSpace, BlendMode blendMode) 686{ 687 688 if (rect.isRounded()) { 689 setCompositeOperation(compositeOperation(), blendMode); 690 fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace); 691 setCompositeOperation(compositeOperation()); 692 } else 693 fillRect(rect.rect(), color, colorSpace, compositeOperation(), blendMode); 694} 695 696#if !USE(CG) && !PLATFORM(QT) 697void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) 698{ 699 if (paintingDisabled()) 700 return; 701 702 Path path; 703 path.addRect(rect); 704 705 if (!roundedHoleRect.radii().isZero()) 706 path.addRoundedRect(roundedHoleRect); 707 else 708 path.addRect(roundedHoleRect.rect()); 709 710 WindRule oldFillRule = fillRule(); 711 Color oldFillColor = fillColor(); 712 ColorSpace oldFillColorSpace = fillColorSpace(); 713 714 setFillRule(RULE_EVENODD); 715 setFillColor(color, colorSpace); 716 717 fillPath(path); 718 719 setFillRule(oldFillRule); 720 setFillColor(oldFillColor, oldFillColorSpace); 721} 722#endif 723 724void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation, BlendMode blendMode) 725{ 726 m_state.compositeOperator = compositeOperation; 727 m_state.blendMode = blendMode; 728 setPlatformCompositeOperation(compositeOperation, blendMode); 729} 730 731CompositeOperator GraphicsContext::compositeOperation() const 732{ 733 return m_state.compositeOperator; 734} 735 736BlendMode GraphicsContext::blendModeOperation() const 737{ 738 return m_state.blendMode; 739} 740 741#if !USE(CG) 742// Implement this if you want to go ahead and push the drawing mode into your native context 743// immediately. 744void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags) 745{ 746} 747#endif 748 749#if !PLATFORM(QT) && !USE(CAIRO) 750void GraphicsContext::setPlatformStrokeStyle(StrokeStyle) 751{ 752} 753#endif 754 755#if !USE(CG) 756void GraphicsContext::setPlatformShouldSmoothFonts(bool) 757{ 758} 759#endif 760 761#if !USE(CG) && !USE(CAIRO) 762bool GraphicsContext::isAcceleratedContext() const 763{ 764 return false; 765} 766#endif 767 768void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle) 769{ 770 // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic 771 // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g., 772 // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave 773 // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. 774 if (penStyle == DottedStroke || penStyle == DashedStroke) { 775 if (p1.x() == p2.x()) { 776 p1.setY(p1.y() + strokeWidth); 777 p2.setY(p2.y() - strokeWidth); 778 } else { 779 p1.setX(p1.x() + strokeWidth); 780 p2.setX(p2.x() - strokeWidth); 781 } 782 } 783 784 if (static_cast<int>(strokeWidth) % 2) { //odd 785 if (p1.x() == p2.x()) { 786 // We're a vertical line. Adjust our x. 787 p1.setX(p1.x() + 0.5f); 788 p2.setX(p2.x() + 0.5f); 789 } else { 790 // We're a horizontal line. Adjust our y. 791 p1.setY(p1.y() + 0.5f); 792 p2.setY(p2.y() + 0.5f); 793 } 794 } 795} 796 797static bool scalesMatch(AffineTransform a, AffineTransform b) 798{ 799 return a.xScale() == b.xScale() && a.yScale() == b.yScale(); 800} 801 802PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size, bool hasAlpha) const 803{ 804 // Make the buffer larger if the context's transform is scaling it so we need a higher 805 // resolution than one pixel per unit. Also set up a corresponding scale factor on the 806 // graphics context. 807 808 AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale); 809 IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale()))); 810 811 OwnPtr<ImageBuffer> buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, ColorSpaceDeviceRGB, this, hasAlpha); 812 if (!buffer) 813 return nullptr; 814 815 buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(), 816 static_cast<float>(scaledSize.height()) / size.height())); 817 818 return buffer.release(); 819} 820 821bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const 822{ 823 GraphicsContext* bufferContext = buffer->context(); 824 825 return scalesMatch(getCTM(), bufferContext->getCTM()) && isAcceleratedContext() == bufferContext->isAcceleratedContext(); 826} 827 828#if !USE(CG) 829void GraphicsContext::platformApplyDeviceScaleFactor(float) 830{ 831} 832#endif 833 834void GraphicsContext::applyDeviceScaleFactor(float deviceScaleFactor) 835{ 836 scale(FloatSize(deviceScaleFactor, deviceScaleFactor)); 837 platformApplyDeviceScaleFactor(deviceScaleFactor); 838} 839 840void GraphicsContext::fillEllipse(const FloatRect& ellipse) 841{ 842 platformFillEllipse(ellipse); 843} 844 845void GraphicsContext::strokeEllipse(const FloatRect& ellipse) 846{ 847 platformStrokeEllipse(ellipse); 848} 849 850void GraphicsContext::fillEllipseAsPath(const FloatRect& ellipse) 851{ 852 Path path; 853 path.addEllipse(ellipse); 854 fillPath(path); 855} 856 857void GraphicsContext::strokeEllipseAsPath(const FloatRect& ellipse) 858{ 859 Path path; 860 path.addEllipse(ellipse); 861 strokePath(path); 862} 863 864#if !USE(CG) 865void GraphicsContext::platformFillEllipse(const FloatRect& ellipse) 866{ 867 if (paintingDisabled()) 868 return; 869 870 fillEllipseAsPath(ellipse); 871} 872 873void GraphicsContext::platformStrokeEllipse(const FloatRect& ellipse) 874{ 875 if (paintingDisabled()) 876 return; 877 878 strokeEllipseAsPath(ellipse); 879} 880#endif 881 882} 883