Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: Source/core/platform/graphics/GraphicsContext.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/GraphicsContext.h ('k') | Source/core/platform/graphics/GraphicsContext3D.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698