1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2013 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 * THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/platform/graphics/GraphicsContext.h" 29 30 #include "core/platform/graphics/BitmapImage.h" 31 #include "core/platform/graphics/Gradient.h" 32 #include "core/platform/graphics/ImageBuffer.h" 33 #include "core/platform/graphics/IntRect.h" 34 #include "core/platform/graphics/RoundedRect.h" 35 #include "core/platform/graphics/TextRunIterator.h" 36 #include "core/platform/graphics/skia/SkiaUtils.h" 37 #include "core/platform/text/BidiResolver.h" 38 #include "third_party/skia/include/core/SkAnnotation.h" 39 #include "third_party/skia/include/core/SkColorFilter.h" 40 #include "third_party/skia/include/core/SkData.h" 41 #include "third_party/skia/include/core/SkDevice.h" 42 #include "third_party/skia/include/core/SkRRect.h" 43 #include "third_party/skia/include/core/SkRefCnt.h" 44 #include "third_party/skia/include/effects/SkBlurMaskFilter.h" 45 #include "third_party/skia/include/effects/SkCornerPathEffect.h" 46 #include "weborigin/KURL.h" 47 #include "wtf/Assertions.h" 48 #include "wtf/MathExtras.h" 49 50 #if OS(DARWIN) 51 #include <ApplicationServices/ApplicationServices.h> 52 #endif 53 54 using namespace std; 55 56 namespace WebCore { 57 58 struct GraphicsContext::DeferredSaveState { 59 DeferredSaveState(unsigned mask, int count) : m_flags(mask), m_restoreCount(count) { } 60 61 unsigned m_flags; 62 int m_restoreCount; 63 }; 64 65 GraphicsContext::GraphicsContext(SkCanvas* canvas) 66 : m_canvas(canvas) 67 , m_deferredSaveFlags(0) 68 , m_annotationMode(0) 69 #if !ASSERT_DISABLED 70 , m_annotationCount(0) 71 , m_transparencyCount(0) 72 #endif 73 , m_trackOpaqueRegion(false) 74 , m_trackTextRegion(false) 75 , m_useHighResMarker(false) 76 , m_updatingControlTints(false) 77 , m_accelerated(false) 78 , m_isCertainlyOpaque(true) 79 , m_printing(false) 80 { 81 m_stateStack.append(adoptPtr(new GraphicsContextState())); 82 m_state = m_stateStack.last().get(); 83 } 84 85 GraphicsContext::~GraphicsContext() 86 { 87 ASSERT(m_stateStack.size() == 1); 88 ASSERT(!m_annotationCount); 89 ASSERT(!m_transparencyCount); 90 } 91 92 const SkBitmap* GraphicsContext::bitmap() const 93 { 94 TRACE_EVENT0("skia", "GraphicsContext::bitmap"); 95 return &m_canvas->getDevice()->accessBitmap(false); 96 } 97 98 const SkBitmap& GraphicsContext::layerBitmap(AccessMode access) const 99 { 100 return m_canvas->getTopDevice()->accessBitmap(access == ReadWrite); 101 } 102 103 SkDevice* GraphicsContext::createCompatibleDevice(const IntSize& size, bool hasAlpha) const 104 { 105 if (paintingDisabled()) 106 return 0; 107 108 return m_canvas->createCompatibleDevice(SkBitmap::kARGB_8888_Config, size.width(), size.height(), !hasAlpha); 109 } 110 111 void GraphicsContext::save() 112 { 113 if (paintingDisabled()) 114 return; 115 116 m_stateStack.append(m_state->clone()); 117 m_state = m_stateStack.last().get(); 118 119 m_saveStateStack.append(DeferredSaveState(m_deferredSaveFlags, m_canvas->getSaveCount())); 120 m_deferredSaveFlags |= SkCanvas::kMatrixClip_SaveFlag; 121 } 122 123 void GraphicsContext::restore() 124 { 125 if (paintingDisabled()) 126 return; 127 128 if (m_stateStack.size() == 1) { 129 LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); 130 return; 131 } 132 133 if (!m_state->m_imageBufferClip.empty()) { 134 applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip); 135 m_canvas->restore(); 136 } 137 138 m_stateStack.removeLast(); 139 m_state = m_stateStack.last().get(); 140 141 DeferredSaveState savedState = m_saveStateStack.last(); 142 m_saveStateStack.removeLast(); 143 m_deferredSaveFlags = savedState.m_flags; 144 m_canvas->restoreToCount(savedState.m_restoreCount); 145 } 146 147 void GraphicsContext::saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags saveFlags) 148 { 149 if (paintingDisabled()) 150 return; 151 152 realizeSave(SkCanvas::kMatrixClip_SaveFlag); 153 154 m_canvas->saveLayer(bounds, paint, saveFlags); 155 if (bounds) 156 m_canvas->clipRect(*bounds); 157 if (m_trackOpaqueRegion) 158 m_opaqueRegion.pushCanvasLayer(paint); 159 } 160 161 void GraphicsContext::restoreLayer() 162 { 163 if (paintingDisabled()) 164 return; 165 166 m_canvas->restore(); 167 if (m_trackOpaqueRegion) 168 m_opaqueRegion.popCanvasLayer(this); 169 } 170 171 void GraphicsContext::beginAnnotation(const GraphicsContextAnnotation& annotation) 172 { 173 if (paintingDisabled()) 174 return; 175 176 canvas()->beginCommentGroup("GraphicsContextAnnotation"); 177 178 AnnotationList annotations; 179 annotation.asAnnotationList(annotations); 180 181 AnnotationList::const_iterator end = annotations.end(); 182 for (AnnotationList::const_iterator it = annotations.begin(); it != end; ++it) 183 canvas()->addComment(it->first, it->second.ascii().data()); 184 185 #if !ASSERT_DISABLED 186 ++m_annotationCount; 187 #endif 188 } 189 190 void GraphicsContext::endAnnotation() 191 { 192 if (paintingDisabled()) 193 return; 194 195 canvas()->endCommentGroup(); 196 197 ASSERT(m_annotationCount > 0); 198 #if !ASSERT_DISABLED 199 --m_annotationCount; 200 #endif 201 } 202 203 void GraphicsContext::setStrokeColor(const Color& color) 204 { 205 m_state->m_strokeData.setColor(color); 206 m_state->m_strokeData.clearGradient(); 207 m_state->m_strokeData.clearPattern(); 208 } 209 210 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) 211 { 212 if (paintingDisabled()) 213 return; 214 215 ASSERT(pattern); 216 if (!pattern) { 217 setStrokeColor(Color::black); 218 return; 219 } 220 m_state->m_strokeData.clearGradient(); 221 m_state->m_strokeData.setPattern(pattern); 222 } 223 224 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) 225 { 226 if (paintingDisabled()) 227 return; 228 229 ASSERT(gradient); 230 if (!gradient) { 231 setStrokeColor(Color::black); 232 return; 233 } 234 m_state->m_strokeData.setGradient(gradient); 235 m_state->m_strokeData.clearPattern(); 236 } 237 238 void GraphicsContext::setFillColor(const Color& color) 239 { 240 m_state->m_fillColor = color; 241 m_state->m_fillGradient.clear(); 242 m_state->m_fillPattern.clear(); 243 } 244 245 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) 246 { 247 if (paintingDisabled()) 248 return; 249 250 ASSERT(pattern); 251 if (!pattern) { 252 setFillColor(Color::black); 253 return; 254 } 255 m_state->m_fillGradient.clear(); 256 m_state->m_fillPattern = pattern; 257 } 258 259 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) 260 { 261 if (paintingDisabled()) 262 return; 263 264 ASSERT(gradient); 265 if (!gradient) { 266 setFillColor(Color::black); 267 return; 268 } 269 m_state->m_fillGradient = gradient; 270 m_state->m_fillPattern.clear(); 271 } 272 273 void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color, 274 DrawLooper::ShadowTransformMode shadowTransformMode, 275 DrawLooper::ShadowAlphaMode shadowAlphaMode) 276 { 277 if (paintingDisabled()) 278 return; 279 280 if (!color.alpha() || (!offset.width() && !offset.height() && !blur)) { 281 clearShadow(); 282 return; 283 } 284 285 DrawLooper drawLooper; 286 drawLooper.addShadow(offset, blur, color, shadowTransformMode, shadowAlphaMode); 287 drawLooper.addUnmodifiedContent(); 288 setDrawLooper(drawLooper); 289 } 290 291 void GraphicsContext::setDrawLooper(const DrawLooper& drawLooper) 292 { 293 if (paintingDisabled()) 294 return; 295 296 m_state->m_looper = drawLooper.skDrawLooper(); 297 } 298 299 void GraphicsContext::clearDrawLooper() 300 { 301 if (paintingDisabled()) 302 return; 303 304 m_state->m_looper.clear(); 305 } 306 307 bool GraphicsContext::hasShadow() const 308 { 309 return !!m_state->m_looper; 310 } 311 312 int GraphicsContext::getNormalizedAlpha() const 313 { 314 int alpha = roundf(m_state->m_alpha * 256); 315 if (alpha > 255) 316 alpha = 255; 317 else if (alpha < 0) 318 alpha = 0; 319 return alpha; 320 } 321 322 bool GraphicsContext::getClipBounds(SkRect* bounds) const 323 { 324 if (paintingDisabled()) 325 return false; 326 return m_canvas->getClipBounds(bounds); 327 } 328 329 const SkMatrix& GraphicsContext::getTotalMatrix() const 330 { 331 if (paintingDisabled()) 332 return SkMatrix::I(); 333 return m_canvas->getTotalMatrix(); 334 } 335 336 bool GraphicsContext::isPrintingDevice() const 337 { 338 if (paintingDisabled()) 339 return false; 340 return m_canvas->getTopDevice()->getDeviceCapabilities() & SkDevice::kVector_Capability; 341 } 342 343 void GraphicsContext::adjustTextRenderMode(SkPaint* paint) 344 { 345 if (paintingDisabled()) 346 return; 347 348 if (!paint->isLCDRenderText()) 349 return; 350 351 paint->setLCDRenderText(couldUseLCDRenderedText()); 352 } 353 354 bool GraphicsContext::couldUseLCDRenderedText() 355 { 356 // Our layers only have a single alpha channel. This means that subpixel 357 // rendered text cannot be composited correctly when the layer is 358 // collapsed. Therefore, subpixel text is disabled when we are drawing 359 // onto a layer. 360 if (paintingDisabled() || isDrawingToLayer() || !isCertainlyOpaque()) 361 return false; 362 363 return shouldSmoothFonts(); 364 } 365 366 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation, BlendMode blendMode) 367 { 368 m_state->m_compositeOperator = compositeOperation; 369 m_state->m_blendMode = blendMode; 370 m_state->m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode); 371 } 372 373 bool GraphicsContext::readPixels(SkBitmap* bitmap, int x, int y, SkCanvas::Config8888 config8888) 374 { 375 if (paintingDisabled()) 376 return false; 377 378 return m_canvas->readPixels(bitmap, x, y, config8888); 379 } 380 381 void GraphicsContext::setMatrix(const SkMatrix& matrix) 382 { 383 if (paintingDisabled()) 384 return; 385 386 realizeSave(SkCanvas::kMatrix_SaveFlag); 387 388 m_canvas->setMatrix(matrix); 389 } 390 391 bool GraphicsContext::concat(const SkMatrix& matrix) 392 { 393 if (paintingDisabled()) 394 return false; 395 396 realizeSave(SkCanvas::kMatrix_SaveFlag); 397 398 return m_canvas->concat(matrix); 399 } 400 401 void GraphicsContext::beginTransparencyLayer(float opacity) 402 { 403 if (paintingDisabled()) 404 return; 405 406 // We need the "alpha" layer flag here because the base layer is opaque 407 // (the surface of the page) but layers on top may have transparent parts. 408 // Without explicitly setting the alpha flag, the layer will inherit the 409 // opaque setting of the base and some things won't work properly. 410 SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag); 411 412 SkPaint layerPaint; 413 layerPaint.setAlpha(static_cast<unsigned char>(opacity * 255)); 414 layerPaint.setXfermodeMode(m_state->m_xferMode); 415 416 saveLayer(0, &layerPaint, saveFlags); 417 418 #if !ASSERT_DISABLED 419 ++m_transparencyCount; 420 #endif 421 } 422 423 void GraphicsContext::endTransparencyLayer() 424 { 425 if (paintingDisabled()) 426 return; 427 428 restoreLayer(); 429 430 ASSERT(m_transparencyCount > 0); 431 #if !ASSERT_DISABLED 432 --m_transparencyCount; 433 #endif 434 } 435 436 void GraphicsContext::clipToImageBuffer(const ImageBuffer* imageBuffer, const FloatRect& rect) 437 { 438 if (paintingDisabled()) 439 return; 440 441 SkRect bounds = WebCoreFloatRectToSKRect(rect); 442 443 if (imageBuffer->internalSize().isEmpty()) { 444 clipRect(bounds); 445 return; 446 } 447 448 // Skia doesn't support clipping to an image, so we create a layer. The next 449 // time restore is invoked the layer and |imageBuffer| are combined to 450 // create the resulting image. 451 m_state->m_clip = bounds; 452 453 // Get the absolute coordinates of the stored clipping rectangle to make it 454 // independent of any transform changes. 455 getTotalMatrix().mapRect(&m_state->m_clip); 456 457 SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag); 458 saveLayer(&bounds, 0, saveFlags); 459 460 const SkBitmap* bitmap = imageBuffer->context()->bitmap(); 461 462 if (m_trackOpaqueRegion) { 463 SkRect opaqueRect = bitmap->isOpaque() ? m_state->m_clip : SkRect::MakeEmpty(); 464 m_opaqueRegion.setImageMask(opaqueRect); 465 } 466 467 // Copy off the image as |imageBuffer| may be deleted before restore is invoked. 468 if (bitmap->isImmutable()) 469 m_state->m_imageBufferClip = *bitmap; 470 else { 471 // We need to make a deep-copy of the pixels themselves, so they don't 472 // change on us between now and when we want to apply them in restore() 473 bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config); 474 } 475 } 476 477 void GraphicsContext::setupPaintForFilling(SkPaint* paint) const 478 { 479 if (paintingDisabled()) 480 return; 481 482 setupPaintCommon(paint); 483 484 setupShader(paint, m_state->m_fillGradient.get(), m_state->m_fillPattern.get(), m_state->m_fillColor.rgb()); 485 } 486 487 float GraphicsContext::setupPaintForStroking(SkPaint* paint, int length) const 488 { 489 if (paintingDisabled()) 490 return 0.0f; 491 492 setupPaintCommon(paint); 493 494 setupShader(paint, m_state->m_strokeData.gradient(), m_state->m_strokeData.pattern(), 495 m_state->m_strokeData.color().rgb()); 496 497 return m_state->m_strokeData.setupPaint(paint, length); 498 } 499 500 void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias) 501 { 502 if (paintingDisabled()) 503 return; 504 505 if (numPoints <= 1) 506 return; 507 508 SkPath path; 509 setPathFromConvexPoints(&path, numPoints, points); 510 511 SkPaint paint; 512 setupPaintForFilling(&paint); 513 paint.setAntiAlias(shouldAntialias); 514 drawPath(path, paint); 515 516 if (strokeStyle() != NoStroke) { 517 paint.reset(); 518 setupPaintForStroking(&paint); 519 drawPath(path, paint); 520 } 521 } 522 523 // This method is only used to draw the little circles used in lists. 524 void GraphicsContext::drawEllipse(const IntRect& elipseRect) 525 { 526 if (paintingDisabled()) 527 return; 528 529 SkRect rect = elipseRect; 530 SkPaint paint; 531 setupPaintForFilling(&paint); 532 drawOval(rect, paint); 533 534 if (strokeStyle() != NoStroke) { 535 paint.reset(); 536 setupPaintForStroking(&paint); 537 drawOval(rect, paint); 538 } 539 } 540 541 void GraphicsContext::drawFocusRing(const Path& focusRingPath, int width, int offset, const Color& color) 542 { 543 // FIXME: Implement support for offset. 544 UNUSED_PARAM(offset); 545 546 if (paintingDisabled()) 547 return; 548 549 SkPaint paint; 550 paint.setAntiAlias(true); 551 paint.setStyle(SkPaint::kStroke_Style); 552 paint.setColor(color.rgb()); 553 554 drawOuterPath(focusRingPath.skPath(), paint, width); 555 drawInnerPath(focusRingPath.skPath(), paint, width); 556 } 557 558 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) 559 { 560 if (paintingDisabled()) 561 return; 562 563 unsigned rectCount = rects.size(); 564 if (!rectCount) 565 return; 566 567 SkRegion focusRingRegion; 568 const int focusRingOutset = getFocusRingOutset(offset); 569 for (unsigned i = 0; i < rectCount; i++) { 570 SkIRect r = rects[i]; 571 r.inset(-focusRingOutset, -focusRingOutset); 572 focusRingRegion.op(r, SkRegion::kUnion_Op); 573 } 574 575 SkPath path; 576 SkPaint paint; 577 paint.setAntiAlias(true); 578 paint.setStyle(SkPaint::kStroke_Style); 579 580 paint.setColor(color.rgb()); 581 focusRingRegion.getBoundaryPath(&path); 582 drawOuterPath(path, paint, width); 583 drawInnerPath(path, paint, width); 584 } 585 586 static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset) 587 { 588 IntRect bounds(holeRect); 589 590 bounds.inflate(shadowBlur); 591 592 if (shadowSpread < 0) 593 bounds.inflate(-shadowSpread); 594 595 IntRect offsetBounds = bounds; 596 offsetBounds.move(-shadowOffset); 597 return unionRect(bounds, offsetBounds); 598 } 599 600 void GraphicsContext::drawInnerShadow(const RoundedRect& rect, const Color& shadowColor, const IntSize shadowOffset, int shadowBlur, int shadowSpread, Edges clippedEdges) 601 { 602 IntRect holeRect(rect.rect()); 603 holeRect.inflate(-shadowSpread); 604 605 if (holeRect.isEmpty()) { 606 if (rect.isRounded()) 607 fillRoundedRect(rect, shadowColor); 608 else 609 fillRect(rect.rect(), shadowColor); 610 return; 611 } 612 613 if (clippedEdges & LeftEdge) { 614 holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0); 615 holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur); 616 } 617 if (clippedEdges & TopEdge) { 618 holeRect.move(0, -max(shadowOffset.height(), 0) - shadowBlur); 619 holeRect.setHeight(holeRect.height() + max(shadowOffset.height(), 0) + shadowBlur); 620 } 621 if (clippedEdges & RightEdge) 622 holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur); 623 if (clippedEdges & BottomEdge) 624 holeRect.setHeight(holeRect.height() - min(shadowOffset.height(), 0) + shadowBlur); 625 626 Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255); 627 628 IntRect outerRect = areaCastingShadowInHole(rect.rect(), shadowBlur, shadowSpread, shadowOffset); 629 RoundedRect roundedHole(holeRect, rect.radii()); 630 631 save(); 632 if (rect.isRounded()) { 633 Path path; 634 path.addRoundedRect(rect); 635 clipPath(path); 636 roundedHole.shrinkRadii(shadowSpread); 637 } else { 638 clip(rect.rect()); 639 } 640 641 DrawLooper drawLooper; 642 drawLooper.addShadow(shadowOffset, shadowBlur, shadowColor, 643 DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); 644 setDrawLooper(drawLooper); 645 fillRectWithRoundedHole(outerRect, roundedHole, fillColor); 646 restore(); 647 clearDrawLooper(); 648 } 649 650 // This is only used to draw borders. 651 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) 652 { 653 if (paintingDisabled()) 654 return; 655 656 StrokeStyle penStyle = strokeStyle(); 657 if (penStyle == NoStroke) 658 return; 659 660 SkPaint paint; 661 FloatPoint p1 = point1; 662 FloatPoint p2 = point2; 663 bool isVerticalLine = (p1.x() == p2.x()); 664 int width = roundf(strokeThickness()); 665 666 // We know these are vertical or horizontal lines, so the length will just 667 // be the sum of the displacement component vectors give or take 1 - 668 // probably worth the speed up of no square root, which also won't be exact. 669 FloatSize disp = p2 - p1; 670 int length = SkScalarRound(disp.width() + disp.height()); 671 setupPaintForStroking(&paint, length); 672 673 if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { 674 // Do a rect fill of our endpoints. This ensures we always have the 675 // appearance of being a border. We then draw the actual dotted/dashed line. 676 677 SkRect r1, r2; 678 r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width); 679 r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width); 680 681 if (isVerticalLine) { 682 r1.offset(-width / 2, 0); 683 r2.offset(-width / 2, -width); 684 } else { 685 r1.offset(0, -width / 2); 686 r2.offset(-width, -width / 2); 687 } 688 SkPaint fillPaint; 689 fillPaint.setColor(paint.getColor()); 690 drawRect(r1, fillPaint); 691 drawRect(r2, fillPaint); 692 } 693 694 adjustLineToPixelBoundaries(p1, p2, width, penStyle); 695 SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; 696 697 m_canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); 698 699 if (m_trackOpaqueRegion) 700 m_opaqueRegion.didDrawPoints(this, SkCanvas::kLines_PointMode, 2, pts, paint); 701 } 702 703 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float width, DocumentMarkerLineStyle style) 704 { 705 if (paintingDisabled()) 706 return; 707 708 int deviceScaleFactor = m_useHighResMarker ? 2 : 1; 709 710 // Create the pattern we'll use to draw the underline. 711 int index = style == DocumentMarkerGrammarLineStyle ? 1 : 0; 712 static SkBitmap* misspellBitmap1x[2] = { 0, 0 }; 713 static SkBitmap* misspellBitmap2x[2] = { 0, 0 }; 714 SkBitmap** misspellBitmap = deviceScaleFactor == 2 ? misspellBitmap2x : misspellBitmap1x; 715 if (!misspellBitmap[index]) { 716 #if OS(DARWIN) 717 // Match the artwork used by the Mac. 718 const int rowPixels = 4 * deviceScaleFactor; 719 const int colPixels = 3 * deviceScaleFactor; 720 misspellBitmap[index] = new SkBitmap; 721 misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, 722 rowPixels, colPixels); 723 misspellBitmap[index]->allocPixels(); 724 725 misspellBitmap[index]->eraseARGB(0, 0, 0, 0); 726 const uint32_t transparentColor = 0x00000000; 727 728 if (deviceScaleFactor == 1) { 729 const uint32_t colors[2][6] = { 730 { 0x2a2a0600, 0x57571000, 0xa8a81b00, 0xbfbf1f00, 0x70701200, 0xe0e02400 }, 731 { 0x2a0f0f0f, 0x571e1e1e, 0xa83d3d3d, 0xbf454545, 0x70282828, 0xe0515151 } 732 }; 733 734 // Pattern: a b a a b a 735 // c d c c d c 736 // e f e e f e 737 for (int x = 0; x < colPixels; ++x) { 738 uint32_t* row = misspellBitmap[index]->getAddr32(0, x); 739 row[0] = colors[index][x * 2]; 740 row[1] = colors[index][x * 2 + 1]; 741 row[2] = colors[index][x * 2]; 742 row[3] = transparentColor; 743 } 744 } else if (deviceScaleFactor == 2) { 745 const uint32_t colors[2][18] = { 746 { 0x0a090101, 0x33320806, 0x55540f0a, 0x37360906, 0x6e6c120c, 0x6e6c120c, 0x7674140d, 0x8d8b1810, 0x8d8b1810, 747 0x96941a11, 0xb3b01f15, 0xb3b01f15, 0x6d6b130c, 0xd9d62619, 0xd9d62619, 0x19180402, 0x7c7a150e, 0xcecb2418 }, 748 { 0x0a020202, 0x33141414, 0x55232323, 0x37161616, 0x6e2e2e2e, 0x6e2e2e2e, 0x76313131, 0x8d3a3a3a, 0x8d3a3a3a, 749 0x963e3e3e, 0xb34b4b4b, 0xb34b4b4b, 0x6d2d2d2d, 0xd95b5b5b, 0xd95b5b5b, 0x19090909, 0x7c343434, 0xce575757 } 750 }; 751 752 // Pattern: a b c c b a 753 // d e f f e d 754 // g h j j h g 755 // k l m m l k 756 // n o p p o n 757 // q r s s r q 758 for (int x = 0; x < colPixels; ++x) { 759 uint32_t* row = misspellBitmap[index]->getAddr32(0, x); 760 row[0] = colors[index][x * 3]; 761 row[1] = colors[index][x * 3 + 1]; 762 row[2] = colors[index][x * 3 + 2]; 763 row[3] = colors[index][x * 3 + 2]; 764 row[4] = colors[index][x * 3 + 1]; 765 row[5] = colors[index][x * 3]; 766 row[6] = transparentColor; 767 row[7] = transparentColor; 768 } 769 } else 770 ASSERT_NOT_REACHED(); 771 #else 772 // We use a 2-pixel-high misspelling indicator because that seems to be 773 // what WebKit is designed for, and how much room there is in a typical 774 // page for it. 775 const int rowPixels = 32 * deviceScaleFactor; // Must be multiple of 4 for pattern below. 776 const int colPixels = 2 * deviceScaleFactor; 777 misspellBitmap[index] = new SkBitmap; 778 misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels); 779 misspellBitmap[index]->allocPixels(); 780 781 misspellBitmap[index]->eraseARGB(0, 0, 0, 0); 782 if (deviceScaleFactor == 1) 783 draw1xMarker(misspellBitmap[index], index); 784 else if (deviceScaleFactor == 2) 785 draw2xMarker(misspellBitmap[index], index); 786 else 787 ASSERT_NOT_REACHED(); 788 #endif 789 } 790 791 #if OS(DARWIN) 792 SkScalar originX = WebCoreFloatToSkScalar(pt.x()) * deviceScaleFactor; 793 SkScalar originY = WebCoreFloatToSkScalar(pt.y()) * deviceScaleFactor; 794 795 // Make sure to draw only complete dots. 796 int rowPixels = misspellBitmap[index]->width(); 797 float widthMod = fmodf(width * deviceScaleFactor, rowPixels); 798 if (rowPixels - widthMod > deviceScaleFactor) 799 width -= widthMod / deviceScaleFactor; 800 #else 801 SkScalar originX = WebCoreFloatToSkScalar(pt.x()); 802 803 // Offset it vertically by 1 so that there's some space under the text. 804 SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1; 805 originX *= deviceScaleFactor; 806 originY *= deviceScaleFactor; 807 #endif 808 809 RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader( 810 *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); 811 SkMatrix matrix; 812 matrix.setTranslate(originX, originY); 813 shader->setLocalMatrix(matrix); 814 815 SkPaint paint; 816 paint.setShader(shader.get()); 817 818 SkRect rect; 819 rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width) * deviceScaleFactor, originY + SkIntToScalar(misspellBitmap[index]->height())); 820 821 if (deviceScaleFactor == 2) { 822 save(); 823 scale(FloatSize(0.5, 0.5)); 824 } 825 drawRect(rect, paint); 826 if (deviceScaleFactor == 2) 827 restore(); 828 } 829 830 void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool printing) 831 { 832 if (paintingDisabled()) 833 return; 834 835 if (width <= 0) 836 return; 837 838 int thickness = SkMax32(static_cast<int>(strokeThickness()), 1); 839 SkRect r; 840 r.fLeft = WebCoreFloatToSkScalar(pt.x()); 841 // Avoid anti-aliasing lines. Currently, these are always horizontal. 842 // Round to nearest pixel to match text and other content. 843 r.fTop = WebCoreFloatToSkScalar(floorf(pt.y() + 0.5f)); 844 r.fRight = r.fLeft + WebCoreFloatToSkScalar(width); 845 r.fBottom = r.fTop + SkIntToScalar(thickness); 846 847 SkPaint paint; 848 switch (strokeStyle()) { 849 case NoStroke: 850 case SolidStroke: 851 case DoubleStroke: 852 case WavyStroke: 853 setupPaintForFilling(&paint); 854 break; 855 case DottedStroke: 856 case DashedStroke: 857 setupPaintForStroking(&paint); 858 break; 859 } 860 861 // Text lines are drawn using the stroke color. 862 paint.setColor(effectiveStrokeColor()); 863 drawRect(r, paint); 864 } 865 866 // Draws a filled rectangle with a stroked border. 867 void GraphicsContext::drawRect(const IntRect& rect) 868 { 869 if (paintingDisabled()) 870 return; 871 872 ASSERT(!rect.isEmpty()); 873 if (rect.isEmpty()) 874 return; 875 876 SkRect skRect = rect; 877 SkPaint paint; 878 int fillcolorNotTransparent = m_state->m_fillColor.rgb() & 0xFF000000; 879 if (fillcolorNotTransparent) { 880 setupPaintForFilling(&paint); 881 drawRect(skRect, paint); 882 } 883 884 if (m_state->m_strokeData.style() != NoStroke && (m_state->m_strokeData.color().rgb() & 0xFF000000)) { 885 // We do a fill of four rects to simulate the stroke of a border. 886 paint.reset(); 887 setupPaintForFilling(&paint); 888 // need to jam in the strokeColor 889 paint.setColor(this->effectiveStrokeColor()); 890 891 SkRect topBorder = { skRect.fLeft, skRect.fTop, skRect.fRight, skRect.fTop + 1 }; 892 drawRect(topBorder, paint); 893 SkRect bottomBorder = { skRect.fLeft, skRect.fBottom - 1, skRect.fRight, skRect.fBottom }; 894 drawRect(bottomBorder, paint); 895 SkRect leftBorder = { skRect.fLeft, skRect.fTop + 1, skRect.fLeft + 1, skRect.fBottom - 1 }; 896 drawRect(leftBorder, paint); 897 SkRect rightBorder = { skRect.fRight - 1, skRect.fTop + 1, skRect.fRight, skRect.fBottom - 1 }; 898 drawRect(rightBorder, paint); 899 } 900 } 901 902 void GraphicsContext::drawText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point) 903 { 904 if (paintingDisabled()) 905 return; 906 907 font.drawText(this, runInfo, point); 908 } 909 910 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) 911 { 912 if (paintingDisabled()) 913 return; 914 915 font.drawEmphasisMarks(this, runInfo, mark, point); 916 } 917 918 void GraphicsContext::drawBidiText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction) 919 { 920 if (paintingDisabled()) 921 return; 922 923 // sub-run painting is not supported for Bidi text. 924 const TextRun& run = runInfo.run; 925 ASSERT((runInfo.from == 0) && (runInfo.to == run.length())); 926 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; 927 bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride())); 928 bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0)); 929 930 // FIXME: This ownership should be reversed. We should pass BidiRunList 931 // to BidiResolver in createBidiRunsForLine. 932 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); 933 bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); 934 if (!bidiRuns.runCount()) 935 return; 936 937 FloatPoint currPoint = point; 938 BidiCharacterRun* bidiRun = bidiRuns.firstRun(); 939 while (bidiRun) { 940 TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start()); 941 bool isRTL = bidiRun->level() % 2; 942 subrun.setDirection(isRTL ? RTL : LTR); 943 subrun.setDirectionalOverride(bidiRun->dirOverride(false)); 944 945 TextRunPaintInfo subrunInfo(subrun); 946 subrunInfo.bounds = runInfo.bounds; 947 font.drawText(this, subrunInfo, currPoint, customFontNotReadyAction); 948 949 bidiRun = bidiRun->next(); 950 // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. 951 if (bidiRun) 952 currPoint.move(font.width(subrun), 0); 953 } 954 955 bidiRuns.deleteRuns(); 956 } 957 958 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, int from, int to) 959 { 960 if (paintingDisabled()) 961 return; 962 963 fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor); 964 } 965 966 void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) 967 { 968 if (!image) 969 return; 970 drawImage(image, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation); 971 } 972 973 void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) 974 { 975 if (!image) 976 return; 977 drawImage(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation, useLowQualityScale); 978 } 979 980 void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation) 981 { 982 drawImage(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, shouldRespectImageOrientation); 983 } 984 985 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) 986 { 987 drawImage(image, dest, src, op, BlendModeNormal, shouldRespectImageOrientation, useLowQualityScale); 988 } 989 990 void GraphicsContext::drawImage(Image* image, const FloatRect& dest) 991 { 992 if (!image) 993 return; 994 drawImage(image, dest, FloatRect(IntRect(IntPoint(), image->size()))); 995 } 996 997 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale) 998 { if (paintingDisabled() || !image) 999 return; 1000 1001 InterpolationQuality previousInterpolationQuality = InterpolationDefault; 1002 1003 if (useLowQualityScale) { 1004 previousInterpolationQuality = imageInterpolationQuality(); 1005 setImageInterpolationQuality(InterpolationLow); 1006 } 1007 1008 image->draw(this, dest, src, op, blendMode, shouldRespectImageOrientation); 1009 1010 if (useLowQualityScale) 1011 setImageInterpolationQuality(previousInterpolationQuality); 1012 } 1013 1014 void GraphicsContext::drawTiledImage(Image* image, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale, BlendMode blendMode) 1015 { 1016 if (paintingDisabled() || !image) 1017 return; 1018 1019 if (useLowQualityScale) { 1020 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 1021 setImageInterpolationQuality(InterpolationLow); 1022 image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode); 1023 setImageInterpolationQuality(previousInterpolationQuality); 1024 } else { 1025 image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode); 1026 } 1027 } 1028 1029 void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, 1030 const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale) 1031 { 1032 if (paintingDisabled() || !image) 1033 return; 1034 1035 if (hRule == Image::StretchTile && vRule == Image::StretchTile) { 1036 // Just do a scale. 1037 drawImage(image, dest, srcRect, op); 1038 return; 1039 } 1040 1041 if (useLowQualityScale) { 1042 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 1043 setImageInterpolationQuality(InterpolationLow); 1044 image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op); 1045 setImageInterpolationQuality(previousInterpolationQuality); 1046 } else { 1047 image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op); 1048 } 1049 } 1050 1051 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& p, CompositeOperator op, BlendMode blendMode) 1052 { 1053 if (!image) 1054 return; 1055 drawImageBuffer(image, FloatRect(IntRect(p, image->logicalSize())), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode); 1056 } 1057 1058 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& r, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 1059 { 1060 if (!image) 1061 return; 1062 drawImageBuffer(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode, useLowQualityScale); 1063 } 1064 1065 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode) 1066 { 1067 drawImageBuffer(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, blendMode); 1068 } 1069 1070 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 1071 { 1072 drawImageBuffer(image, FloatRect(dest), FloatRect(srcRect), op, blendMode, useLowQualityScale); 1073 } 1074 1075 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest) 1076 { 1077 if (!image) 1078 return; 1079 drawImageBuffer(image, dest, FloatRect(IntRect(IntPoint(), image->logicalSize()))); 1080 } 1081 1082 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale) 1083 { 1084 if (paintingDisabled() || !image) 1085 return; 1086 1087 if (useLowQualityScale) { 1088 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); 1089 setImageInterpolationQuality(InterpolationLow); 1090 image->draw(this, dest, src, op, blendMode, useLowQualityScale); 1091 setImageInterpolationQuality(previousInterpolationQuality); 1092 } else { 1093 image->draw(this, dest, src, op, blendMode, useLowQualityScale); 1094 } 1095 } 1096 1097 void GraphicsContext::writePixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) 1098 { 1099 if (paintingDisabled()) 1100 return; 1101 1102 m_canvas->writePixels(bitmap, x, y, config8888); 1103 1104 if (m_trackOpaqueRegion) { 1105 SkRect rect = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 1106 SkPaint paint; 1107 1108 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 1109 m_opaqueRegion.didDrawRect(this, rect, paint, &bitmap); 1110 } 1111 } 1112 1113 void GraphicsContext::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) 1114 { 1115 if (paintingDisabled()) 1116 return; 1117 1118 m_canvas->drawBitmap(bitmap, left, top, paint); 1119 1120 if (m_trackOpaqueRegion) { 1121 SkRect rect = SkRect::MakeXYWH(left, top, bitmap.width(), bitmap.height()); 1122 m_opaqueRegion.didDrawRect(this, rect, *paint, &bitmap); 1123 } 1124 } 1125 1126 void GraphicsContext::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1127 const SkRect& dst, const SkPaint* paint) 1128 { 1129 if (paintingDisabled()) 1130 return; 1131 1132 m_canvas->drawBitmapRectToRect(bitmap, src, dst, paint); 1133 1134 if (m_trackOpaqueRegion) 1135 m_opaqueRegion.didDrawRect(this, dst, *paint, &bitmap); 1136 } 1137 1138 void GraphicsContext::drawOval(const SkRect& oval, const SkPaint& paint) 1139 { 1140 if (paintingDisabled()) 1141 return; 1142 1143 m_canvas->drawOval(oval, paint); 1144 1145 if (m_trackOpaqueRegion) 1146 m_opaqueRegion.didDrawBounded(this, oval, paint); 1147 } 1148 1149 void GraphicsContext::drawPath(const SkPath& path, const SkPaint& paint) 1150 { 1151 if (paintingDisabled()) 1152 return; 1153 1154 m_canvas->drawPath(path, paint); 1155 1156 if (m_trackOpaqueRegion) 1157 m_opaqueRegion.didDrawPath(this, path, paint); 1158 } 1159 1160 void GraphicsContext::drawRect(const SkRect& rect, const SkPaint& paint) 1161 { 1162 if (paintingDisabled()) 1163 return; 1164 1165 m_canvas->drawRect(rect, paint); 1166 1167 if (m_trackOpaqueRegion) 1168 m_opaqueRegion.didDrawRect(this, rect, paint, 0); 1169 } 1170 1171 void GraphicsContext::didDrawRect(const SkRect& rect, const SkPaint& paint, const SkBitmap* bitmap) 1172 { 1173 if (m_trackOpaqueRegion) 1174 m_opaqueRegion.didDrawRect(this, rect, paint, bitmap); 1175 } 1176 1177 void GraphicsContext::drawPosText(const void* text, size_t byteLength, 1178 const SkPoint pos[], const SkRect& textRect, const SkPaint& paint) 1179 { 1180 if (paintingDisabled()) 1181 return; 1182 1183 m_canvas->drawPosText(text, byteLength, pos, paint); 1184 didDrawTextInRect(textRect); 1185 1186 // FIXME: compute bounds for positioned text. 1187 if (m_trackOpaqueRegion) 1188 m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke); 1189 } 1190 1191 void GraphicsContext::drawPosTextH(const void* text, size_t byteLength, 1192 const SkScalar xpos[], SkScalar constY, const SkRect& textRect, const SkPaint& paint) 1193 { 1194 if (paintingDisabled()) 1195 return; 1196 1197 m_canvas->drawPosTextH(text, byteLength, xpos, constY, paint); 1198 didDrawTextInRect(textRect); 1199 1200 // FIXME: compute bounds for positioned text. 1201 if (m_trackOpaqueRegion) 1202 m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke); 1203 } 1204 1205 void GraphicsContext::drawTextOnPath(const void* text, size_t byteLength, 1206 const SkPath& path, const SkRect& textRect, const SkMatrix* matrix, const SkPaint& paint) 1207 { 1208 if (paintingDisabled()) 1209 return; 1210 1211 m_canvas->drawTextOnPath(text, byteLength, path, matrix, paint); 1212 didDrawTextInRect(textRect); 1213 1214 // FIXME: compute bounds for positioned text. 1215 if (m_trackOpaqueRegion) 1216 m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke); 1217 } 1218 1219 void GraphicsContext::fillPath(const Path& pathToFill) 1220 { 1221 if (paintingDisabled() || pathToFill.isEmpty()) 1222 return; 1223 1224 // Use const_cast and temporarily modify the fill type instead of copying the path. 1225 SkPath& path = const_cast<SkPath&>(pathToFill.skPath()); 1226 SkPath::FillType previousFillType = path.getFillType(); 1227 1228 SkPath::FillType temporaryFillType = m_state->m_fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType; 1229 path.setFillType(temporaryFillType); 1230 1231 SkPaint paint; 1232 setupPaintForFilling(&paint); 1233 drawPath(path, paint); 1234 1235 path.setFillType(previousFillType); 1236 } 1237 1238 void GraphicsContext::fillRect(const FloatRect& rect) 1239 { 1240 if (paintingDisabled()) 1241 return; 1242 1243 SkRect r = rect; 1244 1245 SkPaint paint; 1246 setupPaintForFilling(&paint); 1247 drawRect(r, paint); 1248 } 1249 1250 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) 1251 { 1252 if (paintingDisabled()) 1253 return; 1254 1255 SkRect r = rect; 1256 SkPaint paint; 1257 setupPaintCommon(&paint); 1258 paint.setColor(color.rgb()); 1259 drawRect(r, paint); 1260 } 1261 1262 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, 1263 const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) 1264 { 1265 if (paintingDisabled()) 1266 return; 1267 1268 if (topLeft.width() + topRight.width() > rect.width() 1269 || bottomLeft.width() + bottomRight.width() > rect.width() 1270 || topLeft.height() + bottomLeft.height() > rect.height() 1271 || topRight.height() + bottomRight.height() > rect.height()) { 1272 // Not all the radii fit, return a rect. This matches the behavior of 1273 // Path::createRoundedRectangle. Without this we attempt to draw a round 1274 // shadow for a square box. 1275 fillRect(rect, color); 1276 return; 1277 } 1278 1279 SkVector radii[4]; 1280 setRadii(radii, topLeft, topRight, bottomRight, bottomLeft); 1281 1282 SkRRect rr; 1283 rr.setRectRadii(rect, radii); 1284 1285 SkPaint paint; 1286 setupPaintForFilling(&paint); 1287 paint.setColor(color.rgb()); 1288 1289 m_canvas->drawRRect(rr, paint); 1290 1291 if (m_trackOpaqueRegion) 1292 m_opaqueRegion.didDrawBounded(this, rr.getBounds(), paint); 1293 } 1294 1295 void GraphicsContext::fillEllipse(const FloatRect& ellipse) 1296 { 1297 if (paintingDisabled()) 1298 return; 1299 1300 SkRect rect = ellipse; 1301 SkPaint paint; 1302 setupPaintForFilling(&paint); 1303 drawOval(rect, paint); 1304 } 1305 1306 void GraphicsContext::strokePath(const Path& pathToStroke) 1307 { 1308 if (paintingDisabled() || pathToStroke.isEmpty()) 1309 return; 1310 1311 const SkPath& path = pathToStroke.skPath(); 1312 SkPaint paint; 1313 setupPaintForStroking(&paint); 1314 drawPath(path, paint); 1315 } 1316 1317 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) 1318 { 1319 if (paintingDisabled()) 1320 return; 1321 1322 SkPaint paint; 1323 setupPaintForStroking(&paint); 1324 paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); 1325 // strokerect has special rules for CSS when the rect is degenerate: 1326 // if width==0 && height==0, do nothing 1327 // if width==0 || height==0, then just draw line for the other dimension 1328 SkRect r(rect); 1329 bool validW = r.width() > 0; 1330 bool validH = r.height() > 0; 1331 if (validW && validH) { 1332 drawRect(r, paint); 1333 } else if (validW || validH) { 1334 // we are expected to respect the lineJoin, so we can't just call 1335 // drawLine -- we have to create a path that doubles back on itself. 1336 SkPath path; 1337 path.moveTo(r.fLeft, r.fTop); 1338 path.lineTo(r.fRight, r.fBottom); 1339 path.close(); 1340 drawPath(path, paint); 1341 } 1342 } 1343 1344 void GraphicsContext::strokeEllipse(const FloatRect& ellipse) 1345 { 1346 if (paintingDisabled()) 1347 return; 1348 1349 SkRect rect(ellipse); 1350 SkPaint paint; 1351 setupPaintForStroking(&paint); 1352 drawOval(rect, paint); 1353 } 1354 1355 void GraphicsContext::clipRoundedRect(const RoundedRect& rect) 1356 { 1357 if (paintingDisabled()) 1358 return; 1359 1360 SkVector radii[4]; 1361 RoundedRect::Radii wkRadii = rect.radii(); 1362 setRadii(radii, wkRadii.topLeft(), wkRadii.topRight(), wkRadii.bottomRight(), wkRadii.bottomLeft()); 1363 1364 SkRRect r; 1365 r.setRectRadii(rect.rect(), radii); 1366 1367 clipRRect(r, AntiAliased); 1368 } 1369 1370 void GraphicsContext::clipOut(const Path& pathToClip) 1371 { 1372 if (paintingDisabled()) 1373 return; 1374 1375 // Use const_cast and temporarily toggle the inverse fill type instead of copying the path. 1376 SkPath& path = const_cast<SkPath&>(pathToClip.skPath()); 1377 path.toggleInverseFillType(); 1378 clipPath(path, AntiAliased); 1379 path.toggleInverseFillType(); 1380 } 1381 1382 void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) 1383 { 1384 if (paintingDisabled() || pathToClip.isEmpty()) 1385 return; 1386 1387 // Use const_cast and temporarily modify the fill type instead of copying the path. 1388 SkPath& path = const_cast<SkPath&>(pathToClip.skPath()); 1389 SkPath::FillType previousFillType = path.getFillType(); 1390 1391 SkPath::FillType temporaryFillType = clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType; 1392 path.setFillType(temporaryFillType); 1393 clipPath(path, AntiAliased); 1394 1395 path.setFillType(previousFillType); 1396 } 1397 1398 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased) 1399 { 1400 if (paintingDisabled()) 1401 return; 1402 1403 if (numPoints <= 1) 1404 return; 1405 1406 SkPath path; 1407 setPathFromConvexPoints(&path, numPoints, points); 1408 clipPath(path, antialiased ? AntiAliased : NotAntiAliased); 1409 } 1410 1411 void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect) 1412 { 1413 if (paintingDisabled()) 1414 return; 1415 1416 if (!rect.isRounded()) { 1417 clipOut(rect.rect()); 1418 return; 1419 } 1420 1421 Path path; 1422 path.addRoundedRect(rect); 1423 clipOut(path); 1424 } 1425 1426 void GraphicsContext::canvasClip(const Path& pathToClip, WindRule clipRule) 1427 { 1428 if (paintingDisabled()) 1429 return; 1430 1431 // Use const_cast and temporarily modify the fill type instead of copying the path. 1432 SkPath& path = const_cast<SkPath&>(pathToClip.skPath()); 1433 SkPath::FillType previousFillType = path.getFillType(); 1434 1435 SkPath::FillType temporaryFillType = clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType; 1436 path.setFillType(temporaryFillType); 1437 clipPath(path); 1438 1439 path.setFillType(previousFillType); 1440 } 1441 1442 bool GraphicsContext::clipRect(const SkRect& rect, AntiAliasingMode aa, SkRegion::Op op) 1443 { 1444 if (paintingDisabled()) 1445 return false; 1446 1447 realizeSave(SkCanvas::kClip_SaveFlag); 1448 1449 return m_canvas->clipRect(rect, op, aa == AntiAliased); 1450 } 1451 1452 bool GraphicsContext::clipPath(const SkPath& path, AntiAliasingMode aa, SkRegion::Op op) 1453 { 1454 if (paintingDisabled()) 1455 return false; 1456 1457 realizeSave(SkCanvas::kClip_SaveFlag); 1458 1459 return m_canvas->clipPath(path, op, aa == AntiAliased); 1460 } 1461 1462 bool GraphicsContext::clipRRect(const SkRRect& rect, AntiAliasingMode aa, SkRegion::Op op) 1463 { 1464 if (paintingDisabled()) 1465 return false; 1466 1467 realizeSave(SkCanvas::kClip_SaveFlag); 1468 1469 return m_canvas->clipRRect(rect, op, aa == AntiAliased); 1470 } 1471 1472 void GraphicsContext::rotate(float angleInRadians) 1473 { 1474 if (paintingDisabled()) 1475 return; 1476 1477 realizeSave(SkCanvas::kMatrix_SaveFlag); 1478 1479 m_canvas->rotate(WebCoreFloatToSkScalar(angleInRadians * (180.0f / 3.14159265f))); 1480 } 1481 1482 void GraphicsContext::translate(float w, float h) 1483 { 1484 if (paintingDisabled()) 1485 return; 1486 1487 realizeSave(SkCanvas::kMatrix_SaveFlag); 1488 1489 m_canvas->translate(WebCoreFloatToSkScalar(w), WebCoreFloatToSkScalar(h)); 1490 } 1491 1492 void GraphicsContext::scale(const FloatSize& size) 1493 { 1494 if (paintingDisabled()) 1495 return; 1496 1497 realizeSave(SkCanvas::kMatrix_SaveFlag); 1498 1499 m_canvas->scale(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height())); 1500 } 1501 1502 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) 1503 { 1504 if (paintingDisabled()) 1505 return; 1506 1507 SkAutoDataUnref url(SkData::NewWithCString(link.string().utf8().data())); 1508 SkAnnotateRectWithURL(m_canvas, destRect, url.get()); 1509 } 1510 1511 void GraphicsContext::setURLFragmentForRect(const String& destName, const IntRect& rect) 1512 { 1513 if (paintingDisabled()) 1514 return; 1515 1516 SkAutoDataUnref skDestName(SkData::NewWithCString(destName.utf8().data())); 1517 SkAnnotateLinkToDestination(m_canvas, rect, skDestName.get()); 1518 } 1519 1520 void GraphicsContext::addURLTargetAtPoint(const String& name, const IntPoint& pos) 1521 { 1522 if (paintingDisabled()) 1523 return; 1524 1525 SkAutoDataUnref nameData(SkData::NewWithCString(name.utf8().data())); 1526 SkAnnotateNamedDestination(m_canvas, SkPoint::Make(pos.x(), pos.y()), nameData); 1527 } 1528 1529 AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const 1530 { 1531 if (paintingDisabled()) 1532 return AffineTransform(); 1533 1534 const SkMatrix& m = getTotalMatrix(); 1535 return AffineTransform(SkScalarToDouble(m.getScaleX()), 1536 SkScalarToDouble(m.getSkewY()), 1537 SkScalarToDouble(m.getSkewX()), 1538 SkScalarToDouble(m.getScaleY()), 1539 SkScalarToDouble(m.getTranslateX()), 1540 SkScalarToDouble(m.getTranslateY())); 1541 } 1542 1543 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, CompositeOperator op) 1544 { 1545 if (paintingDisabled()) 1546 return; 1547 1548 CompositeOperator previousOperator = compositeOperation(); 1549 setCompositeOperation(op); 1550 fillRect(rect, color); 1551 setCompositeOperation(previousOperator); 1552 } 1553 1554 void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color) 1555 { 1556 if (rect.isRounded()) 1557 fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color); 1558 else 1559 fillRect(rect.rect(), color); 1560 } 1561 1562 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color) 1563 { 1564 if (paintingDisabled()) 1565 return; 1566 1567 Path path; 1568 path.addRect(rect); 1569 1570 if (!roundedHoleRect.radii().isZero()) 1571 path.addRoundedRect(roundedHoleRect); 1572 else 1573 path.addRect(roundedHoleRect.rect()); 1574 1575 WindRule oldFillRule = fillRule(); 1576 Color oldFillColor = fillColor(); 1577 1578 setFillRule(RULE_EVENODD); 1579 setFillColor(color); 1580 1581 fillPath(path); 1582 1583 setFillRule(oldFillRule); 1584 setFillColor(oldFillColor); 1585 } 1586 1587 void GraphicsContext::clearRect(const FloatRect& rect) 1588 { 1589 if (paintingDisabled()) 1590 return; 1591 1592 SkRect r = rect; 1593 SkPaint paint; 1594 setupPaintForFilling(&paint); 1595 paint.setXfermodeMode(SkXfermode::kClear_Mode); 1596 drawRect(r, paint); 1597 } 1598 1599 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle) 1600 { 1601 // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic 1602 // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g., 1603 // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave 1604 // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. 1605 if (penStyle == DottedStroke || penStyle == DashedStroke) { 1606 if (p1.x() == p2.x()) { 1607 p1.setY(p1.y() + strokeWidth); 1608 p2.setY(p2.y() - strokeWidth); 1609 } else { 1610 p1.setX(p1.x() + strokeWidth); 1611 p2.setX(p2.x() - strokeWidth); 1612 } 1613 } 1614 1615 if (static_cast<int>(strokeWidth) % 2) { //odd 1616 if (p1.x() == p2.x()) { 1617 // We're a vertical line. Adjust our x. 1618 p1.setX(p1.x() + 0.5f); 1619 p2.setX(p2.x() + 0.5f); 1620 } else { 1621 // We're a horizontal line. Adjust our y. 1622 p1.setY(p1.y() + 0.5f); 1623 p2.setY(p2.y() + 0.5f); 1624 } 1625 } 1626 } 1627 1628 static bool scalesMatch(AffineTransform a, AffineTransform b) 1629 { 1630 return a.xScale() == b.xScale() && a.yScale() == b.yScale(); 1631 } 1632 1633 PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size, bool hasAlpha) const 1634 { 1635 // Make the buffer larger if the context's transform is scaling it so we need a higher 1636 // resolution than one pixel per unit. Also set up a corresponding scale factor on the 1637 // graphics context. 1638 1639 AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale); 1640 IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale()))); 1641 1642 OwnPtr<ImageBuffer> buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, this, hasAlpha); 1643 if (!buffer) 1644 return nullptr; 1645 1646 buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(), 1647 static_cast<float>(scaledSize.height()) / size.height())); 1648 1649 return buffer.release(); 1650 } 1651 1652 bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const 1653 { 1654 GraphicsContext* bufferContext = buffer->context(); 1655 1656 return scalesMatch(getCTM(), bufferContext->getCTM()) && m_accelerated == bufferContext->isAccelerated(); 1657 } 1658 1659 void GraphicsContext::addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle) 1660 { 1661 SkIRect ir; 1662 int rx = SkMin32(SkScalarRound(rect.width()), size.width()); 1663 int ry = SkMin32(SkScalarRound(rect.height()), size.height()); 1664 1665 ir.set(-rx, -ry, rx, ry); 1666 switch (startAngle) { 1667 case 0: 1668 ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom); 1669 break; 1670 case 90: 1671 ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom); 1672 break; 1673 case 180: 1674 ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop); 1675 break; 1676 case 270: 1677 ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop); 1678 break; 1679 default: 1680 ASSERT(0); 1681 } 1682 1683 SkRect r; 1684 r.set(ir); 1685 path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false); 1686 } 1687 1688 void GraphicsContext::setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points) 1689 { 1690 path->incReserve(numPoints); 1691 path->moveTo(WebCoreFloatToSkScalar(points[0].x()), 1692 WebCoreFloatToSkScalar(points[0].y())); 1693 for (size_t i = 1; i < numPoints; ++i) { 1694 path->lineTo(WebCoreFloatToSkScalar(points[i].x()), 1695 WebCoreFloatToSkScalar(points[i].y())); 1696 } 1697 1698 /* The code used to just blindly call this 1699 path->setIsConvex(true); 1700 But webkit can sometimes send us non-convex 4-point values, so we mark the path's 1701 convexity as unknown, so it will get computed by skia at draw time. 1702 See crbug.com 108605 1703 */ 1704 SkPath::Convexity convexity = SkPath::kConvex_Convexity; 1705 if (numPoints == 4) 1706 convexity = SkPath::kUnknown_Convexity; 1707 path->setConvexity(convexity); 1708 } 1709 1710 void GraphicsContext::setupPaintCommon(SkPaint* paint) const 1711 { 1712 #if defined(SK_DEBUG) 1713 { 1714 SkPaint defaultPaint; 1715 SkASSERT(*paint == defaultPaint); 1716 } 1717 #endif 1718 1719 paint->setAntiAlias(m_state->m_shouldAntialias); 1720 paint->setXfermodeMode(m_state->m_xferMode); 1721 paint->setLooper(m_state->m_looper.get()); 1722 } 1723 1724 void GraphicsContext::drawOuterPath(const SkPath& path, SkPaint& paint, int width) 1725 { 1726 #if OS(DARWIN) 1727 paint.setAlpha(64); 1728 paint.setStrokeWidth(width); 1729 paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref(); 1730 #else 1731 paint.setStrokeWidth(1); 1732 paint.setPathEffect(new SkCornerPathEffect(1))->unref(); 1733 #endif 1734 drawPath(path, paint); 1735 } 1736 1737 void GraphicsContext::drawInnerPath(const SkPath& path, SkPaint& paint, int width) 1738 { 1739 #if OS(DARWIN) 1740 paint.setAlpha(128); 1741 paint.setStrokeWidth(width * 0.5f); 1742 drawPath(path, paint); 1743 #endif 1744 } 1745 1746 void GraphicsContext::setRadii(SkVector* radii, IntSize topLeft, IntSize topRight, IntSize bottomRight, IntSize bottomLeft) 1747 { 1748 radii[SkRRect::kUpperLeft_Corner].set(SkIntToScalar(topLeft.width()), 1749 SkIntToScalar(topLeft.height())); 1750 radii[SkRRect::kUpperRight_Corner].set(SkIntToScalar(topRight.width()), 1751 SkIntToScalar(topRight.height())); 1752 radii[SkRRect::kLowerRight_Corner].set(SkIntToScalar(bottomRight.width()), 1753 SkIntToScalar(bottomRight.height())); 1754 radii[SkRRect::kLowerLeft_Corner].set(SkIntToScalar(bottomLeft.width()), 1755 SkIntToScalar(bottomLeft.height())); 1756 } 1757 1758 #if OS(DARWIN) 1759 CGColorSpaceRef deviceRGBColorSpaceRef() 1760 { 1761 static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB(); 1762 return deviceSpace; 1763 } 1764 #else 1765 void GraphicsContext::draw2xMarker(SkBitmap* bitmap, int index) 1766 { 1767 const SkPMColor lineColor = lineColors(index); 1768 const SkPMColor antiColor1 = antiColors1(index); 1769 const SkPMColor antiColor2 = antiColors2(index); 1770 1771 uint32_t* row1 = bitmap->getAddr32(0, 0); 1772 uint32_t* row2 = bitmap->getAddr32(0, 1); 1773 uint32_t* row3 = bitmap->getAddr32(0, 2); 1774 uint32_t* row4 = bitmap->getAddr32(0, 3); 1775 1776 // Pattern: X0o o0X0o o0 1777 // XX0o o0XXX0o o0X 1778 // o0XXX0o o0XXX0o 1779 // o0X0o o0X0o 1780 const SkPMColor row1Color[] = { lineColor, antiColor1, antiColor2, 0, 0, 0, antiColor2, antiColor1 }; 1781 const SkPMColor row2Color[] = { lineColor, lineColor, antiColor1, antiColor2, 0, antiColor2, antiColor1, lineColor }; 1782 const SkPMColor row3Color[] = { 0, antiColor2, antiColor1, lineColor, lineColor, lineColor, antiColor1, antiColor2 }; 1783 const SkPMColor row4Color[] = { 0, 0, antiColor2, antiColor1, lineColor, antiColor1, antiColor2, 0 }; 1784 1785 for (int x = 0; x < bitmap->width() + 8; x += 8) { 1786 int count = std::min(bitmap->width() - x, 8); 1787 if (count > 0) { 1788 memcpy(row1 + x, row1Color, count * sizeof(SkPMColor)); 1789 memcpy(row2 + x, row2Color, count * sizeof(SkPMColor)); 1790 memcpy(row3 + x, row3Color, count * sizeof(SkPMColor)); 1791 memcpy(row4 + x, row4Color, count * sizeof(SkPMColor)); 1792 } 1793 } 1794 } 1795 1796 void GraphicsContext::draw1xMarker(SkBitmap* bitmap, int index) 1797 { 1798 const uint32_t lineColor = lineColors(index); 1799 const uint32_t antiColor = antiColors2(index); 1800 1801 // Pattern: X o o X o o X 1802 // o X o o X o 1803 uint32_t* row1 = bitmap->getAddr32(0, 0); 1804 uint32_t* row2 = bitmap->getAddr32(0, 1); 1805 for (int x = 0; x < bitmap->width(); x++) { 1806 switch (x % 4) { 1807 case 0: 1808 row1[x] = lineColor; 1809 break; 1810 case 1: 1811 row1[x] = antiColor; 1812 row2[x] = antiColor; 1813 break; 1814 case 2: 1815 row2[x] = lineColor; 1816 break; 1817 case 3: 1818 row1[x] = antiColor; 1819 row2[x] = antiColor; 1820 break; 1821 } 1822 } 1823 } 1824 1825 const SkPMColor GraphicsContext::lineColors(int index) 1826 { 1827 static const SkPMColor colors[] = { 1828 SkPreMultiplyARGB(0xFF, 0xFF, 0x00, 0x00), // Opaque red. 1829 SkPreMultiplyARGB(0xFF, 0xC0, 0xC0, 0xC0) // Opaque gray. 1830 }; 1831 1832 return colors[index]; 1833 } 1834 1835 const SkPMColor GraphicsContext::antiColors1(int index) 1836 { 1837 static const SkPMColor colors[] = { 1838 SkPreMultiplyARGB(0xB0, 0xFF, 0x00, 0x00), // Semitransparent red. 1839 SkPreMultiplyARGB(0xB0, 0xC0, 0xC0, 0xC0) // Semitransparent gray. 1840 }; 1841 1842 return colors[index]; 1843 } 1844 1845 const SkPMColor GraphicsContext::antiColors2(int index) 1846 { 1847 static const SkPMColor colors[] = { 1848 SkPreMultiplyARGB(0x60, 0xFF, 0x00, 0x00), // More transparent red 1849 SkPreMultiplyARGB(0x60, 0xC0, 0xC0, 0xC0) // More transparent gray 1850 }; 1851 1852 return colors[index]; 1853 } 1854 #endif 1855 1856 void GraphicsContext::setupShader(SkPaint* paint, Gradient* grad, Pattern* pat, SkColor color) const 1857 { 1858 RefPtr<SkShader> shader; 1859 1860 if (grad) { 1861 shader = grad->shader(); 1862 color = SK_ColorBLACK; 1863 } else if (pat) { 1864 shader = pat->shader(); 1865 color = SK_ColorBLACK; 1866 paint->setFilterBitmap(imageInterpolationQuality() != InterpolationNone); 1867 } 1868 1869 paint->setColor(m_state->applyAlpha(color)); 1870 paint->setShader(shader.get()); 1871 } 1872 1873 1874 void GraphicsContext::applyClipFromImage(const SkRect& rect, const SkBitmap& imageBuffer) 1875 { 1876 if (paintingDisabled()) 1877 return; 1878 1879 // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we 1880 // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping. 1881 SkPaint paint; 1882 paint.setXfermodeMode(SkXfermode::kDstIn_Mode); 1883 realizeSave(SkCanvas::kMatrixClip_SaveFlag); 1884 m_canvas->save(SkCanvas::kMatrix_SaveFlag); 1885 m_canvas->resetMatrix(); 1886 m_canvas->drawBitmapRect(imageBuffer, 0, rect, &paint); 1887 m_canvas->restore(); 1888 } 1889 1890 void GraphicsContext::didDrawTextInRect(const SkRect& textRect) 1891 { 1892 if (m_trackTextRegion) { 1893 TRACE_EVENT0("skia", "PlatformContextSkia::trackTextRegion"); 1894 m_textRegion.join(textRect); 1895 } 1896 } 1897 1898 } 1899