1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2009 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 "Font.h" 31 #include "Generator.h" 32 #include "ImageBuffer.h" 33 #include "IntRect.h" 34 #include "RoundedIntRect.h" 35 #include "TextRun.h" 36 37 using namespace std; 38 39 namespace WebCore { 40 41 class TextRunIterator { 42 public: 43 TextRunIterator() 44 : m_textRun(0) 45 , m_offset(0) 46 { 47 } 48 49 TextRunIterator(const TextRun* textRun, unsigned offset) 50 : m_textRun(textRun) 51 , m_offset(offset) 52 { 53 } 54 55 TextRunIterator(const TextRunIterator& other) 56 : m_textRun(other.m_textRun) 57 , m_offset(other.m_offset) 58 { 59 } 60 61 unsigned offset() const { return m_offset; } 62 void increment() { m_offset++; } 63 bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); } 64 UChar current() const { return (*m_textRun)[m_offset]; } 65 WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); } 66 67 bool operator==(const TextRunIterator& other) 68 { 69 return m_offset == other.m_offset && m_textRun == other.m_textRun; 70 } 71 72 bool operator!=(const TextRunIterator& other) { return !operator==(other); } 73 74 private: 75 const TextRun* m_textRun; 76 int m_offset; 77 }; 78 79 GraphicsContext::GraphicsContext(PlatformGraphicsContext* platformGraphicsContext) 80 : m_updatingControlTints(false) 81 { 82 platformInit(platformGraphicsContext); 83 } 84 85 GraphicsContext::~GraphicsContext() 86 { 87 platformDestroy(); 88 } 89 90 void GraphicsContext::save() 91 { 92 if (paintingDisabled()) 93 return; 94 95 m_stack.append(m_state); 96 97 savePlatformState(); 98 } 99 100 void GraphicsContext::restore() 101 { 102 if (paintingDisabled()) 103 return; 104 105 if (m_stack.isEmpty()) { 106 LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); 107 return; 108 } 109 m_state = m_stack.last(); 110 m_stack.removeLast(); 111 112 restorePlatformState(); 113 } 114 115 void GraphicsContext::setStrokeThickness(float thickness) 116 { 117 m_state.strokeThickness = thickness; 118 setPlatformStrokeThickness(thickness); 119 } 120 121 void GraphicsContext::setStrokeStyle(StrokeStyle style) 122 { 123 m_state.strokeStyle = style; 124 setPlatformStrokeStyle(style); 125 } 126 127 void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace) 128 { 129 m_state.strokeColor = color; 130 m_state.strokeColorSpace = colorSpace; 131 m_state.strokeGradient.clear(); 132 m_state.strokePattern.clear(); 133 setPlatformStrokeColor(color, colorSpace); 134 } 135 136 void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace) 137 { 138 m_state.shadowOffset = offset; 139 m_state.shadowBlur = blur; 140 m_state.shadowColor = color; 141 m_state.shadowColorSpace = colorSpace; 142 setPlatformShadow(offset, blur, color, colorSpace); 143 } 144 145 void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace) 146 { 147 m_state.shadowOffset = offset; 148 m_state.shadowBlur = blur; 149 m_state.shadowColor = color; 150 m_state.shadowColorSpace = colorSpace; 151 #if USE(CG) 152 m_state.shadowsUseLegacyRadius = true; 153 #endif 154 setPlatformShadow(offset, blur, color, colorSpace); 155 } 156 157 void GraphicsContext::clearShadow() 158 { 159 m_state.shadowOffset = FloatSize(); 160 m_state.shadowBlur = 0; 161 m_state.shadowColor = Color(); 162 m_state.shadowColorSpace = ColorSpaceDeviceRGB; 163 clearPlatformShadow(); 164 } 165 166 bool GraphicsContext::hasShadow() const 167 { 168 return m_state.shadowColor.isValid() && m_state.shadowColor.alpha() 169 && (m_state.shadowBlur || m_state.shadowOffset.width() || m_state.shadowOffset.height()); 170 } 171 172 bool GraphicsContext::getShadow(FloatSize& offset, float& blur, Color& color, ColorSpace& colorSpace) const 173 { 174 offset = m_state.shadowOffset; 175 blur = m_state.shadowBlur; 176 color = m_state.shadowColor; 177 colorSpace = m_state.shadowColorSpace; 178 179 return hasShadow(); 180 } 181 182 float GraphicsContext::strokeThickness() const 183 { 184 return m_state.strokeThickness; 185 } 186 187 StrokeStyle GraphicsContext::strokeStyle() const 188 { 189 return m_state.strokeStyle; 190 } 191 192 Color GraphicsContext::strokeColor() const 193 { 194 return m_state.strokeColor; 195 } 196 197 ColorSpace GraphicsContext::strokeColorSpace() const 198 { 199 return m_state.strokeColorSpace; 200 } 201 202 WindRule GraphicsContext::fillRule() const 203 { 204 return m_state.fillRule; 205 } 206 207 void GraphicsContext::setFillRule(WindRule fillRule) 208 { 209 m_state.fillRule = fillRule; 210 } 211 212 void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace) 213 { 214 m_state.fillColor = color; 215 m_state.fillColorSpace = colorSpace; 216 m_state.fillGradient.clear(); 217 m_state.fillPattern.clear(); 218 setPlatformFillColor(color, colorSpace); 219 } 220 221 Color GraphicsContext::fillColor() const 222 { 223 return m_state.fillColor; 224 } 225 226 ColorSpace GraphicsContext::fillColorSpace() const 227 { 228 return m_state.fillColorSpace; 229 } 230 231 void GraphicsContext::setShouldAntialias(bool b) 232 { 233 m_state.shouldAntialias = b; 234 setPlatformShouldAntialias(b); 235 } 236 237 bool GraphicsContext::shouldAntialias() const 238 { 239 return m_state.shouldAntialias; 240 } 241 242 void GraphicsContext::setShouldSmoothFonts(bool b) 243 { 244 m_state.shouldSmoothFonts = b; 245 setPlatformShouldSmoothFonts(b); 246 } 247 248 bool GraphicsContext::shouldSmoothFonts() const 249 { 250 return m_state.shouldSmoothFonts; 251 } 252 253 const GraphicsContextState& GraphicsContext::state() const 254 { 255 return m_state; 256 } 257 258 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) 259 { 260 ASSERT(pattern); 261 if (!pattern) { 262 setStrokeColor(Color::black, ColorSpaceDeviceRGB); 263 return; 264 } 265 m_state.strokeGradient.clear(); 266 m_state.strokePattern = pattern; 267 setPlatformStrokePattern(m_state.strokePattern.get()); 268 } 269 270 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) 271 { 272 ASSERT(pattern); 273 if (!pattern) { 274 setFillColor(Color::black, ColorSpaceDeviceRGB); 275 return; 276 } 277 m_state.fillGradient.clear(); 278 m_state.fillPattern = pattern; 279 setPlatformFillPattern(m_state.fillPattern.get()); 280 } 281 282 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) 283 { 284 ASSERT(gradient); 285 if (!gradient) { 286 setStrokeColor(Color::black, ColorSpaceDeviceRGB); 287 return; 288 } 289 m_state.strokeGradient = gradient; 290 m_state.strokePattern.clear(); 291 setPlatformStrokeGradient(m_state.strokeGradient.get()); 292 } 293 294 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) 295 { 296 ASSERT(gradient); 297 if (!gradient) { 298 setFillColor(Color::black, ColorSpaceDeviceRGB); 299 return; 300 } 301 m_state.fillGradient = gradient; 302 m_state.fillPattern.clear(); 303 setPlatformFillGradient(m_state.fillGradient.get()); 304 } 305 306 Gradient* GraphicsContext::fillGradient() const 307 { 308 return m_state.fillGradient.get(); 309 } 310 311 Gradient* GraphicsContext::strokeGradient() const 312 { 313 return m_state.strokeGradient.get(); 314 } 315 316 Pattern* GraphicsContext::fillPattern() const 317 { 318 return m_state.fillPattern.get(); 319 } 320 321 Pattern* GraphicsContext::strokePattern() const 322 { 323 return m_state.strokePattern.get(); 324 } 325 326 void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms) 327 { 328 m_state.shadowsIgnoreTransforms = ignoreTransforms; 329 } 330 331 bool GraphicsContext::shadowsIgnoreTransforms() const 332 { 333 return m_state.shadowsIgnoreTransforms; 334 } 335 336 bool GraphicsContext::updatingControlTints() const 337 { 338 return m_updatingControlTints; 339 } 340 341 void GraphicsContext::setUpdatingControlTints(bool b) 342 { 343 setPaintingDisabled(b); 344 m_updatingControlTints = b; 345 } 346 347 void GraphicsContext::setPaintingDisabled(bool f) 348 { 349 m_state.paintingDisabled = f; 350 } 351 352 bool GraphicsContext::paintingDisabled() const 353 { 354 return m_state.paintingDisabled; 355 } 356 357 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op) 358 { 359 drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op); 360 } 361 362 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale) 363 { 364 drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); 365 } 366 367 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) 368 { 369 drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op); 370 } 371 372 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) 373 { 374 drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale); 375 } 376 377 #if !OS(WINCE) || PLATFORM(QT) 378 void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to) 379 { 380 if (paintingDisabled()) 381 return; 382 383 font.drawText(this, run, point, from, to); 384 } 385 #endif 386 387 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) 388 { 389 if (paintingDisabled()) 390 return; 391 392 font.drawEmphasisMarks(this, run, mark, point, from, to); 393 } 394 395 void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point) 396 { 397 if (paintingDisabled()) 398 return; 399 400 // FIXME: This ownership should be reversed. We should pass BidiRunList 401 // to BidiResolver in createBidiRunsForLine. 402 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; 403 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); 404 405 WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; 406 407 bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); 408 409 bidiResolver.setPosition(TextRunIterator(&run, 0)); 410 bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); 411 412 if (!bidiRuns.runCount()) 413 return; 414 415 FloatPoint currPoint = point; 416 BidiCharacterRun* bidiRun = bidiRuns.firstRun(); 417 while (bidiRun) { 418 419 TextRun subrun = run; 420 subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start()); 421 subrun.setRTL(bidiRun->level() % 2); 422 subrun.setDirectionalOverride(bidiRun->dirOverride(false)); 423 424 font.drawText(this, subrun, currPoint); 425 426 bidiRun = bidiRun->next(); 427 // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. 428 if (bidiRun) 429 currPoint.move(font.width(subrun), 0); 430 } 431 432 bidiRuns.deleteRuns(); 433 } 434 435 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) 436 { 437 if (paintingDisabled()) 438 return; 439 440 fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace); 441 } 442 443 void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) 444 { 445 if (paintingDisabled() || !image) 446 return; 447 448 float tsw = src.width(); 449 float tsh = src.height(); 450 float tw = dest.width(); 451 float th = dest.height(); 452 453 if (tsw == -1) 454 tsw = image->width(); 455 if (tsh == -1) 456 tsh = image->height(); 457 458 if (tw == -1) 459 tw = image->width(); 460 if (th == -1) 461 th = image->height(); 462 463 if (useLowQualityScale) { 464 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 465 // FIXME: Should be InterpolationLow 466 setImageInterpolationQuality(InterpolationNone); 467 image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op); 468 setImageInterpolationQuality(previousInterpolationQuality); 469 } else 470 image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op); 471 } 472 473 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale) 474 { 475 if (paintingDisabled() || !image) 476 return; 477 478 if (useLowQualityScale) { 479 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 480 setImageInterpolationQuality(InterpolationLow); 481 image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op); 482 setImageInterpolationQuality(previousInterpolationQuality); 483 } else 484 image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op); 485 } 486 487 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale) 488 { 489 if (paintingDisabled() || !image) 490 return; 491 492 if (hRule == Image::StretchTile && vRule == Image::StretchTile) { 493 // Just do a scale. 494 drawImage(image, styleColorSpace, dest, srcRect, op); 495 return; 496 } 497 498 if (useLowQualityScale) { 499 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 500 setImageInterpolationQuality(InterpolationLow); 501 image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op); 502 setImageInterpolationQuality(previousInterpolationQuality); 503 } else 504 image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op); 505 } 506 507 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op) 508 { 509 drawImageBuffer(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op); 510 } 511 512 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale) 513 { 514 drawImageBuffer(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); 515 } 516 517 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) 518 { 519 drawImageBuffer(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op); 520 } 521 522 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) 523 { 524 drawImageBuffer(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale); 525 } 526 527 void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) 528 { 529 if (paintingDisabled() || !image) 530 return; 531 532 float tsw = src.width(); 533 float tsh = src.height(); 534 float tw = dest.width(); 535 float th = dest.height(); 536 537 if (tsw == -1) 538 tsw = image->width(); 539 if (tsh == -1) 540 tsh = image->height(); 541 542 if (tw == -1) 543 tw = image->width(); 544 if (th == -1) 545 th = image->height(); 546 547 if (useLowQualityScale) { 548 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 549 // FIXME: Should be InterpolationLow 550 setImageInterpolationQuality(InterpolationNone); 551 image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale); 552 setImageInterpolationQuality(previousInterpolationQuality); 553 } else 554 image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale); 555 } 556 557 #if !PLATFORM(QT) 558 void GraphicsContext::clip(const IntRect& rect) 559 { 560 clip(FloatRect(rect)); 561 } 562 #endif 563 564 void GraphicsContext::addRoundedRectClip(const RoundedIntRect& rect) 565 { 566 if (paintingDisabled()) 567 return; 568 569 Path path; 570 path.addRoundedRect(rect); 571 clip(path); 572 } 573 574 void GraphicsContext::clipOutRoundedRect(const RoundedIntRect& rect) 575 { 576 if (paintingDisabled()) 577 return; 578 579 Path path; 580 path.addRoundedRect(rect); 581 clipOut(path); 582 } 583 584 void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect) 585 { 586 if (paintingDisabled()) 587 return; 588 buffer->clip(this, rect); 589 } 590 591 #if !USE(CG) 592 IntRect GraphicsContext::clipBounds() const 593 { 594 ASSERT_NOT_REACHED(); 595 return IntRect(); 596 } 597 #endif 598 599 TextDrawingModeFlags GraphicsContext::textDrawingMode() const 600 { 601 return m_state.textDrawingMode; 602 } 603 604 void GraphicsContext::setTextDrawingMode(TextDrawingModeFlags mode) 605 { 606 m_state.textDrawingMode = mode; 607 if (paintingDisabled()) 608 return; 609 setPlatformTextDrawingMode(mode); 610 } 611 612 void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator) 613 { 614 if (paintingDisabled()) 615 return; 616 generator.fill(this, rect); 617 } 618 619 void GraphicsContext::fillRoundedRect(const RoundedIntRect& rect, const Color& color, ColorSpace colorSpace) 620 { 621 fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace); 622 } 623 624 #if !USE(CG) 625 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) 626 { 627 if (paintingDisabled()) 628 return; 629 630 Path path; 631 path.addRect(rect); 632 633 if (!roundedHoleRect.radii().isZero()) 634 path.addRoundedRect(roundedHoleRect); 635 else 636 path.addRect(roundedHoleRect.rect()); 637 638 WindRule oldFillRule = fillRule(); 639 Color oldFillColor = fillColor(); 640 ColorSpace oldFillColorSpace = fillColorSpace(); 641 642 setFillRule(RULE_EVENODD); 643 setFillColor(color, colorSpace); 644 645 fillPath(path); 646 647 setFillRule(oldFillRule); 648 setFillColor(oldFillColor, oldFillColorSpace); 649 } 650 #endif 651 652 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation) 653 { 654 m_state.compositeOperator = compositeOperation; 655 setPlatformCompositeOperation(compositeOperation); 656 } 657 658 CompositeOperator GraphicsContext::compositeOperation() const 659 { 660 return m_state.compositeOperator; 661 } 662 663 #if !(USE(SKIA) && !PLATFORM(ANDROID)) 664 void GraphicsContext::setPlatformFillGradient(Gradient*) 665 { 666 } 667 668 void GraphicsContext::setPlatformFillPattern(Pattern*) 669 { 670 } 671 672 void GraphicsContext::setPlatformStrokeGradient(Gradient*) 673 { 674 } 675 676 void GraphicsContext::setPlatformStrokePattern(Pattern*) 677 { 678 } 679 #endif 680 681 #if !USE(CG) && !(USE(SKIA) && !PLATFORM(ANDROID)) 682 // Implement this if you want to go ahead and push the drawing mode into your native context 683 // immediately. 684 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) 685 { 686 } 687 #endif 688 689 #if !PLATFORM(QT) && !USE(CAIRO) && !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG) 690 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle) 691 { 692 } 693 #endif 694 695 #if !USE(CG) 696 void GraphicsContext::setPlatformShouldSmoothFonts(bool) 697 { 698 } 699 #endif 700 701 #if !USE(SKIA) 702 void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&) 703 { 704 } 705 706 void GraphicsContext::syncSoftwareCanvas() 707 { 708 } 709 710 void GraphicsContext::markDirtyRect(const IntRect&) 711 { 712 } 713 #endif 714 715 716 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle) 717 { 718 // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic 719 // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g., 720 // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave 721 // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. 722 if (penStyle == DottedStroke || penStyle == DashedStroke) { 723 if (p1.x() == p2.x()) { 724 p1.setY(p1.y() + strokeWidth); 725 p2.setY(p2.y() - strokeWidth); 726 } else { 727 p1.setX(p1.x() + strokeWidth); 728 p2.setX(p2.x() - strokeWidth); 729 } 730 } 731 732 if (static_cast<int>(strokeWidth) % 2) { //odd 733 if (p1.x() == p2.x()) { 734 // We're a vertical line. Adjust our x. 735 p1.setX(p1.x() + 0.5f); 736 p2.setX(p2.x() + 0.5f); 737 } else { 738 // We're a horizontal line. Adjust our y. 739 p1.setY(p1.y() + 0.5f); 740 p2.setY(p2.y() + 0.5f); 741 } 742 } 743 } 744 745 } 746