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