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