1/*
2 * Copyright (c) 2006, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "GraphicsContext.h"
33
34#include "AffineTransform.h"
35#include "Color.h"
36#include "FloatRect.h"
37#include "GLES2Canvas.h"
38#include "Gradient.h"
39#include "GraphicsContextPlatformPrivate.h"
40#include "ImageBuffer.h"
41#include "IntRect.h"
42#include "NativeImageSkia.h"
43#include "NotImplemented.h"
44#include "PlatformContextSkia.h"
45
46#include "SkBitmap.h"
47#include "SkBlurMaskFilter.h"
48#include "SkColorFilter.h"
49#include "SkCornerPathEffect.h"
50#include "SkLayerDrawLooper.h"
51#include "SkShader.h"
52#include "SkiaUtils.h"
53#include "skia/ext/platform_canvas.h"
54
55#include <math.h>
56#include <wtf/Assertions.h>
57#include <wtf/MathExtras.h>
58#include <wtf/UnusedParam.h>
59
60using namespace std;
61
62namespace WebCore {
63
64namespace {
65
66inline int fastMod(int value, int max)
67{
68    int sign = SkExtractSign(value);
69
70    value = SkApplySign(value, sign);
71    if (value >= max)
72        value %= max;
73    return SkApplySign(value, sign);
74}
75
76inline float square(float n)
77{
78    return n * n;
79}
80
81}  // namespace
82
83// "Seatbelt" functions ------------------------------------------------------
84//
85// These functions check certain graphics primitives for being "safe".
86// Skia has historically crashed when sent crazy data. These functions do
87// additional checking to prevent crashes.
88//
89// Ideally, all of these would be fixed in the graphics layer and we would not
90// have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA
91// flag to check the graphics layer.
92
93// Disabling these checks (20/01/2010), since we think we've fixed all the Skia
94// bugs.  Leaving the code in for now, so we can revert easily if necessary.
95// #define ENSURE_VALUE_SAFETY_FOR_SKIA
96
97#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
98static bool isCoordinateSkiaSafe(float coord)
99{
100    // First check for valid floats.
101#if defined(_MSC_VER)
102    if (!_finite(coord))
103#else
104    if (!finite(coord))
105#endif
106        return false;
107
108    // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If
109    // the transformed point exceeds 15 bits, we just declare that it's
110    // unreasonable to catch both of these cases.
111    static const int maxPointMagnitude = 32767;
112    if (coord > maxPointMagnitude || coord < -maxPointMagnitude)
113        return false;
114
115    return true;
116}
117#endif
118
119static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt)
120{
121#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
122    // Now check for points that will overflow. We check the *transformed*
123    // points since this is what will be rasterized.
124    SkPoint xPt;
125    transform.mapPoints(&xPt, &pt, 1);
126    return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);
127#else
128    return true;
129#endif
130}
131
132static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc)
133{
134#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
135    SkPoint topleft = {rc.fLeft, rc.fTop};
136    SkPoint bottomright = {rc.fRight, rc.fBottom};
137    return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);
138#else
139    return true;
140#endif
141}
142
143bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path)
144{
145#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
146    SkPoint current_points[4];
147    SkPath::Iter iter(path, false);
148    for (SkPath::Verb verb = iter.next(current_points);
149         verb != SkPath::kDone_Verb;
150         verb = iter.next(current_points)) {
151        switch (verb) {
152        case SkPath::kMove_Verb:
153            // This move will be duplicated in the next verb, so we can ignore.
154            break;
155        case SkPath::kLine_Verb:
156            // iter.next returns 2 points.
157            if (!isPointSkiaSafe(transform, current_points[0])
158                || !isPointSkiaSafe(transform, current_points[1]))
159                return false;
160            break;
161        case SkPath::kQuad_Verb:
162            // iter.next returns 3 points.
163            if (!isPointSkiaSafe(transform, current_points[0])
164                || !isPointSkiaSafe(transform, current_points[1])
165                || !isPointSkiaSafe(transform, current_points[2]))
166                return false;
167            break;
168        case SkPath::kCubic_Verb:
169            // iter.next returns 4 points.
170            if (!isPointSkiaSafe(transform, current_points[0])
171                || !isPointSkiaSafe(transform, current_points[1])
172                || !isPointSkiaSafe(transform, current_points[2])
173                || !isPointSkiaSafe(transform, current_points[3]))
174                return false;
175            break;
176        case SkPath::kClose_Verb:
177        case SkPath::kDone_Verb:
178        default:
179            break;
180        }
181    }
182    return true;
183#else
184    return true;
185#endif
186}
187
188// Local helper functions ------------------------------------------------------
189
190void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
191{
192    SkIRect ir;
193    int rx = SkMin32(SkScalarRound(rect.width()), size.width());
194    int ry = SkMin32(SkScalarRound(rect.height()), size.height());
195
196    ir.set(-rx, -ry, rx, ry);
197    switch (startAngle) {
198    case 0:
199        ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
200        break;
201    case 90:
202        ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
203        break;
204    case 180:
205        ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
206        break;
207    case 270:
208        ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
209        break;
210    default:
211        ASSERT(0);
212    }
213
214    SkRect r;
215    r.set(ir);
216    path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
217}
218
219// -----------------------------------------------------------------------------
220
221// This may be called with a NULL pointer to create a graphics context that has
222// no painting.
223void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
224{
225    m_data = new GraphicsContextPlatformPrivate(gc);
226    setPaintingDisabled(!gc || !platformContext()->canvas());
227}
228
229void GraphicsContext::platformDestroy()
230{
231    delete m_data;
232}
233
234PlatformGraphicsContext* GraphicsContext::platformContext() const
235{
236    ASSERT(!paintingDisabled());
237    return m_data->context();
238}
239
240// State saving ----------------------------------------------------------------
241
242void GraphicsContext::savePlatformState()
243{
244    if (paintingDisabled())
245        return;
246
247    if (platformContext()->useGPU())
248        platformContext()->gpuCanvas()->save();
249
250    // Save our private State.
251    platformContext()->save();
252}
253
254void GraphicsContext::restorePlatformState()
255{
256    if (paintingDisabled())
257        return;
258
259    if (platformContext()->useGPU())
260        platformContext()->gpuCanvas()->restore();
261
262    // Restore our private State.
263    platformContext()->restore();
264}
265
266void GraphicsContext::beginTransparencyLayer(float opacity)
267{
268    if (paintingDisabled())
269        return;
270
271    // We need the "alpha" layer flag here because the base layer is opaque
272    // (the surface of the page) but layers on top may have transparent parts.
273    // Without explicitly setting the alpha flag, the layer will inherit the
274    // opaque setting of the base and some things won't work properly.
275    platformContext()->canvas()->saveLayerAlpha(
276        0,
277        static_cast<unsigned char>(opacity * 255),
278        static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
279                                         SkCanvas::kFullColorLayer_SaveFlag));
280}
281
282void GraphicsContext::endTransparencyLayer()
283{
284    if (paintingDisabled())
285        return;
286    platformContext()->canvas()->restore();
287}
288
289// Graphics primitives ---------------------------------------------------------
290
291void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
292{
293    if (paintingDisabled())
294        return;
295
296    SkRect r(rect);
297    if (!isRectSkiaSafe(getCTM(), r))
298        return;
299
300    platformContext()->prepareForSoftwareDraw();
301    SkPath path;
302    path.addOval(r, SkPath::kCW_Direction);
303    // only perform the inset if we won't invert r
304    if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
305        // Adding one to the thickness doesn't make the border too thick as
306        // it's painted over afterwards. But without this adjustment the
307        // border appears a little anemic after anti-aliasing.
308        r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
309        path.addOval(r, SkPath::kCCW_Direction);
310    }
311    platformContext()->clipPathAntiAliased(path);
312}
313
314void GraphicsContext::clearPlatformShadow()
315{
316    if (paintingDisabled())
317        return;
318    platformContext()->setDrawLooper(0);
319}
320
321void GraphicsContext::clearRect(const FloatRect& rect)
322{
323    if (paintingDisabled())
324        return;
325
326    if (platformContext()->useGPU() && !platformContext()->canvasClipApplied()) {
327        platformContext()->prepareForHardwareDraw();
328        platformContext()->gpuCanvas()->clearRect(rect);
329        return;
330    }
331
332    // Force a readback here (if we're using the GPU), since clearRect() is
333    // incompatible with mixed-mode rendering.
334    platformContext()->syncSoftwareCanvas();
335
336    SkRect r = rect;
337    if (!isRectSkiaSafe(getCTM(), r))
338        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
339
340    SkPaint paint;
341    platformContext()->setupPaintForFilling(&paint);
342    paint.setXfermodeMode(SkXfermode::kClear_Mode);
343    platformContext()->canvas()->drawRect(r, paint);
344}
345
346void GraphicsContext::clip(const FloatRect& rect)
347{
348    if (paintingDisabled())
349        return;
350
351    SkRect r(rect);
352    if (!isRectSkiaSafe(getCTM(), r))
353        return;
354
355    platformContext()->prepareForSoftwareDraw();
356    platformContext()->canvas()->clipRect(r);
357}
358
359void GraphicsContext::clip(const Path& path)
360{
361    if (paintingDisabled())
362        return;
363
364    const SkPath& p = *path.platformPath();
365    if (!isPathSkiaSafe(getCTM(), p))
366        return;
367
368    platformContext()->prepareForSoftwareDraw();
369    platformContext()->clipPathAntiAliased(p);
370}
371
372void GraphicsContext::canvasClip(const Path& path)
373{
374    if (paintingDisabled())
375        return;
376
377    if (platformContext()->useGPU())
378        platformContext()->gpuCanvas()->clipPath(path);
379
380    const SkPath& p = *path.platformPath();
381    if (!isPathSkiaSafe(getCTM(), p))
382        return;
383
384    platformContext()->canvasClipPath(p);
385}
386
387void GraphicsContext::clipOut(const IntRect& rect)
388{
389    if (paintingDisabled())
390        return;
391
392    SkRect r(rect);
393    if (!isRectSkiaSafe(getCTM(), r))
394        return;
395
396    platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
397}
398
399void GraphicsContext::clipOut(const Path& p)
400{
401    if (paintingDisabled())
402        return;
403
404    if (platformContext()->useGPU())
405        platformContext()->gpuCanvas()->clipOut(p);
406
407    const SkPath& path = *p.platformPath();
408    if (!isPathSkiaSafe(getCTM(), path))
409        return;
410
411    platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
412}
413
414void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
415{
416    if (paintingDisabled())
417        return;
418
419    if (platformContext()->useGPU())
420        platformContext()->gpuCanvas()->clipPath(pathToClip);
421
422    SkPath path = *pathToClip.platformPath();
423    if (!isPathSkiaSafe(getCTM(), path))
424        return;
425
426    path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
427    platformContext()->clipPathAntiAliased(path);
428}
429
430void GraphicsContext::concatCTM(const AffineTransform& affine)
431{
432    if (paintingDisabled())
433        return;
434
435    if (platformContext()->useGPU())
436        platformContext()->gpuCanvas()->concatCTM(affine);
437
438    platformContext()->canvas()->concat(affine);
439}
440
441void GraphicsContext::setCTM(const AffineTransform& affine)
442{
443    if (paintingDisabled())
444        return;
445
446    if (platformContext()->useGPU())
447        platformContext()->gpuCanvas()->setCTM(affine);
448
449    platformContext()->canvas()->setMatrix(affine);
450}
451
452void GraphicsContext::drawConvexPolygon(size_t numPoints,
453                                        const FloatPoint* points,
454                                        bool shouldAntialias)
455{
456    if (paintingDisabled())
457        return;
458
459    if (numPoints <= 1)
460        return;
461
462    platformContext()->prepareForSoftwareDraw();
463
464    SkPath path;
465
466    path.incReserve(numPoints);
467    path.moveTo(WebCoreFloatToSkScalar(points[0].x()),
468                WebCoreFloatToSkScalar(points[0].y()));
469    for (size_t i = 1; i < numPoints; i++) {
470        path.lineTo(WebCoreFloatToSkScalar(points[i].x()),
471                    WebCoreFloatToSkScalar(points[i].y()));
472    }
473
474    if (!isPathSkiaSafe(getCTM(), path))
475        return;
476
477    SkPaint paint;
478    platformContext()->setupPaintForFilling(&paint);
479    platformContext()->canvas()->drawPath(path, paint);
480
481    if (strokeStyle() != NoStroke) {
482        paint.reset();
483        platformContext()->setupPaintForStroking(&paint, 0, 0);
484        platformContext()->canvas()->drawPath(path, paint);
485    }
486}
487
488void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
489{
490    if (paintingDisabled())
491        return;
492
493    if (numPoints <= 1)
494        return;
495
496    // FIXME: IMPLEMENT!!
497}
498
499// This method is only used to draw the little circles used in lists.
500void GraphicsContext::drawEllipse(const IntRect& elipseRect)
501{
502    if (paintingDisabled())
503        return;
504
505    SkRect rect = elipseRect;
506    if (!isRectSkiaSafe(getCTM(), rect))
507        return;
508
509    platformContext()->prepareForSoftwareDraw();
510    SkPaint paint;
511    platformContext()->setupPaintForFilling(&paint);
512    platformContext()->canvas()->drawOval(rect, paint);
513
514    if (strokeStyle() != NoStroke) {
515        paint.reset();
516        platformContext()->setupPaintForStroking(&paint, &rect, 0);
517        platformContext()->canvas()->drawOval(rect, paint);
518    }
519}
520
521void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
522{
523    // FIXME: implement
524}
525
526void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
527{
528    if (paintingDisabled())
529        return;
530
531    unsigned rectCount = rects.size();
532    if (!rectCount)
533        return;
534
535    platformContext()->prepareForSoftwareDraw();
536    SkRegion focusRingRegion;
537    const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5);
538    for (unsigned i = 0; i < rectCount; i++) {
539        SkIRect r = rects[i];
540        r.inset(-focusRingOutset, -focusRingOutset);
541        focusRingRegion.op(r, SkRegion::kUnion_Op);
542    }
543
544    SkPath path;
545    SkPaint paint;
546    paint.setAntiAlias(true);
547    paint.setStyle(SkPaint::kStroke_Style);
548
549    paint.setColor(color.rgb());
550    paint.setStrokeWidth(focusRingOutset * 2);
551    paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
552    focusRingRegion.getBoundaryPath(&path);
553    platformContext()->canvas()->drawPath(path, paint);
554}
555
556// This is only used to draw borders.
557void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
558{
559    if (paintingDisabled())
560        return;
561
562    StrokeStyle penStyle = strokeStyle();
563    if (penStyle == NoStroke)
564        return;
565
566    SkPaint paint;
567    if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
568        return;
569
570    platformContext()->prepareForSoftwareDraw();
571
572    FloatPoint p1 = point1;
573    FloatPoint p2 = point2;
574    bool isVerticalLine = (p1.x() == p2.x());
575    int width = roundf(strokeThickness());
576
577    // We know these are vertical or horizontal lines, so the length will just
578    // be the sum of the displacement component vectors give or take 1 -
579    // probably worth the speed up of no square root, which also won't be exact.
580    FloatSize disp = p2 - p1;
581    int length = SkScalarRound(disp.width() + disp.height());
582    platformContext()->setupPaintForStroking(&paint, 0, length);
583
584    if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
585        // Do a rect fill of our endpoints.  This ensures we always have the
586        // appearance of being a border.  We then draw the actual dotted/dashed line.
587
588        SkRect r1, r2;
589        r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
590        r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
591
592        if (isVerticalLine) {
593            r1.offset(-width / 2, 0);
594            r2.offset(-width / 2, -width);
595        } else {
596            r1.offset(0, -width / 2);
597            r2.offset(-width, -width / 2);
598        }
599        SkPaint fillPaint;
600        fillPaint.setColor(paint.getColor());
601        platformContext()->canvas()->drawRect(r1, fillPaint);
602        platformContext()->canvas()->drawRect(r2, fillPaint);
603    }
604
605    adjustLineToPixelBoundaries(p1, p2, width, penStyle);
606    SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
607
608    platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
609}
610
611void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle style)
612{
613    if (paintingDisabled())
614        return;
615
616    platformContext()->prepareForSoftwareDraw();
617
618    // Create the pattern we'll use to draw the underline.
619    static SkBitmap* misspellBitmap = 0;
620    if (!misspellBitmap) {
621        // We use a 2-pixel-high misspelling indicator because that seems to be
622        // what WebKit is designed for, and how much room there is in a typical
623        // page for it.
624        const int rowPixels = 32;  // Must be multiple of 4 for pattern below.
625        const int colPixels = 2;
626        misspellBitmap = new SkBitmap;
627        misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
628                                   rowPixels, colPixels);
629        misspellBitmap->allocPixels();
630
631        misspellBitmap->eraseARGB(0, 0, 0, 0);
632        const uint32_t lineColor = 0xFFFF0000;  // Opaque red.
633        const uint32_t antiColor = 0x60600000;  // Semitransparent red.
634
635        // Pattern:  X o   o X o   o X
636        //             o X o   o X o
637        uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
638        uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
639        for (int x = 0; x < rowPixels; x++) {
640            switch (x % 4) {
641            case 0:
642                row1[x] = lineColor;
643                break;
644            case 1:
645                row1[x] = antiColor;
646                row2[x] = antiColor;
647                break;
648            case 2:
649                row2[x] = lineColor;
650                break;
651            case 3:
652                row1[x] = antiColor;
653                row2[x] = antiColor;
654                break;
655            }
656        }
657    }
658
659    // Offset it vertically by 1 so that there's some space under the text.
660    SkScalar originX = WebCoreFloatToSkScalar(pt.x());
661    SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
662
663    // Make a shader for the bitmap with an origin of the box we'll draw. This
664    // shader is refcounted and will have an initial refcount of 1.
665    SkShader* shader = SkShader::CreateBitmapShader(
666        *misspellBitmap, SkShader::kRepeat_TileMode,
667        SkShader::kRepeat_TileMode);
668    SkMatrix matrix;
669    matrix.reset();
670    matrix.postTranslate(originX, originY);
671    shader->setLocalMatrix(matrix);
672
673    // Assign the shader to the paint & release our reference. The paint will
674    // now own the shader and the shader will be destroyed when the paint goes
675    // out of scope.
676    SkPaint paint;
677    paint.setShader(shader);
678    shader->unref();
679
680    SkRect rect;
681    rect.set(originX,
682             originY,
683             originX + WebCoreFloatToSkScalar(width),
684             originY + SkIntToScalar(misspellBitmap->height()));
685    platformContext()->canvas()->drawRect(rect, paint);
686}
687
688void GraphicsContext::drawLineForText(const FloatPoint& pt,
689                                      float width,
690                                      bool printing)
691{
692    if (paintingDisabled())
693        return;
694
695    if (width <= 0)
696        return;
697
698    platformContext()->prepareForSoftwareDraw();
699
700    int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
701    SkRect r;
702    r.fLeft = WebCoreFloatToSkScalar(pt.x());
703    r.fTop = WebCoreFloatToSkScalar(pt.y());
704    r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
705    r.fBottom = r.fTop + SkIntToScalar(thickness);
706
707    SkPaint paint;
708    platformContext()->setupPaintForFilling(&paint);
709    // Text lines are drawn using the stroke color.
710    paint.setColor(platformContext()->effectiveStrokeColor());
711    platformContext()->canvas()->drawRect(r, paint);
712}
713
714// Draws a filled rectangle with a stroked border.
715void GraphicsContext::drawRect(const IntRect& rect)
716{
717    if (paintingDisabled())
718        return;
719
720    platformContext()->prepareForSoftwareDraw();
721
722    SkRect r = rect;
723    if (!isRectSkiaSafe(getCTM(), r)) {
724        // See the fillRect below.
725        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
726    }
727
728    platformContext()->drawRect(r);
729}
730
731void GraphicsContext::fillPath(const Path& pathToFill)
732{
733    if (paintingDisabled())
734        return;
735
736    // FIXME: add support to GLES2Canvas for more than just solid fills.
737    if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
738        platformContext()->prepareForHardwareDraw();
739        platformContext()->gpuCanvas()->fillPath(pathToFill);
740        return;
741    }
742
743    SkPath path = *pathToFill.platformPath();
744    if (!isPathSkiaSafe(getCTM(), path))
745      return;
746
747    platformContext()->prepareForSoftwareDraw();
748
749    const GraphicsContextState& state = m_state;
750    path.setFillType(state.fillRule == RULE_EVENODD ?
751        SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
752
753    SkPaint paint;
754    platformContext()->setupPaintForFilling(&paint);
755
756    platformContext()->canvas()->drawPath(path, paint);
757}
758
759void GraphicsContext::fillRect(const FloatRect& rect)
760{
761    if (paintingDisabled())
762        return;
763
764    SkRect r = rect;
765    if (!isRectSkiaSafe(getCTM(), r)) {
766        // See the other version of fillRect below.
767        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
768    }
769
770    if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
771        platformContext()->prepareForHardwareDraw();
772        platformContext()->gpuCanvas()->fillRect(rect);
773        return;
774    }
775
776    platformContext()->save();
777
778    platformContext()->prepareForSoftwareDraw();
779
780    SkPaint paint;
781    platformContext()->setupPaintForFilling(&paint);
782    platformContext()->canvas()->drawRect(r, paint);
783
784    platformContext()->restore();
785}
786
787void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
788{
789    if (paintingDisabled())
790        return;
791
792    if (platformContext()->useGPU() && platformContext()->canAccelerate()) {
793        platformContext()->prepareForHardwareDraw();
794        platformContext()->gpuCanvas()->fillRect(rect, color, colorSpace);
795        return;
796    }
797
798    platformContext()->prepareForSoftwareDraw();
799
800    SkRect r = rect;
801    if (!isRectSkiaSafe(getCTM(), r)) {
802        // Special case when the rectangle overflows fixed point. This is a
803        // workaround to fix bug 1212844. When the input rectangle is very
804        // large, it can overflow Skia's internal fixed point rect. This
805        // should be fixable in Skia (since the output bitmap isn't that
806        // large), but until that is fixed, we try to handle it ourselves.
807        //
808        // We manually clip the rectangle to the current clip rect. This
809        // will prevent overflow. The rectangle will be transformed to the
810        // canvas' coordinate space before it is converted to fixed point
811        // so we are guaranteed not to overflow after doing this.
812        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
813    }
814
815    SkPaint paint;
816    platformContext()->setupPaintCommon(&paint);
817    paint.setColor(color.rgb());
818    platformContext()->canvas()->drawRect(r, paint);
819}
820
821void GraphicsContext::fillRoundedRect(const IntRect& rect,
822                                      const IntSize& topLeft,
823                                      const IntSize& topRight,
824                                      const IntSize& bottomLeft,
825                                      const IntSize& bottomRight,
826                                      const Color& color,
827                                      ColorSpace colorSpace)
828{
829    if (paintingDisabled())
830        return;
831
832    platformContext()->prepareForSoftwareDraw();
833
834    SkRect r = rect;
835    if (!isRectSkiaSafe(getCTM(), r))
836        // See fillRect().
837        ClipRectToCanvas(*platformContext()->canvas(), r, &r);
838
839    if (topLeft.width() + topRight.width() > rect.width()
840            || bottomLeft.width() + bottomRight.width() > rect.width()
841            || topLeft.height() + bottomLeft.height() > rect.height()
842            || topRight.height() + bottomRight.height() > rect.height()) {
843        // Not all the radii fit, return a rect. This matches the behavior of
844        // Path::createRoundedRectangle. Without this we attempt to draw a round
845        // shadow for a square box.
846        fillRect(rect, color, colorSpace);
847        return;
848    }
849
850    SkPath path;
851    addCornerArc(&path, r, topRight, 270);
852    addCornerArc(&path, r, bottomRight, 0);
853    addCornerArc(&path, r, bottomLeft, 90);
854    addCornerArc(&path, r, topLeft, 180);
855
856    SkPaint paint;
857    platformContext()->setupPaintForFilling(&paint);
858    paint.setColor(color.rgb());
859    platformContext()->canvas()->drawPath(path, paint);
860}
861
862AffineTransform GraphicsContext::getCTM() const
863{
864    const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
865    return AffineTransform(SkScalarToDouble(m.getScaleX()),
866                           SkScalarToDouble(m.getSkewY()),
867                           SkScalarToDouble(m.getSkewX()),
868                           SkScalarToDouble(m.getScaleY()),
869                           SkScalarToDouble(m.getTranslateX()),
870                           SkScalarToDouble(m.getTranslateY()));
871}
872
873FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode)
874{
875    return rect;
876}
877
878void GraphicsContext::scale(const FloatSize& size)
879{
880    if (paintingDisabled())
881        return;
882
883    if (platformContext()->useGPU())
884        platformContext()->gpuCanvas()->scale(size);
885
886    platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
887        WebCoreFloatToSkScalar(size.height()));
888}
889
890void GraphicsContext::setAlpha(float alpha)
891{
892    if (paintingDisabled())
893        return;
894
895    if (platformContext()->useGPU())
896        platformContext()->gpuCanvas()->setAlpha(alpha);
897
898    platformContext()->setAlpha(alpha);
899}
900
901void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
902{
903    if (paintingDisabled())
904        return;
905
906    if (platformContext()->useGPU())
907        platformContext()->gpuCanvas()->setCompositeOperation(op);
908
909    platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
910}
911
912InterpolationQuality GraphicsContext::imageInterpolationQuality() const
913{
914    return platformContext()->interpolationQuality();
915}
916
917void GraphicsContext::setImageInterpolationQuality(InterpolationQuality q)
918{
919    platformContext()->setInterpolationQuality(q);
920}
921
922void GraphicsContext::setLineCap(LineCap cap)
923{
924    if (paintingDisabled())
925        return;
926    switch (cap) {
927    case ButtCap:
928        platformContext()->setLineCap(SkPaint::kButt_Cap);
929        break;
930    case RoundCap:
931        platformContext()->setLineCap(SkPaint::kRound_Cap);
932        break;
933    case SquareCap:
934        platformContext()->setLineCap(SkPaint::kSquare_Cap);
935        break;
936    default:
937        ASSERT(0);
938        break;
939    }
940}
941
942void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
943{
944    if (paintingDisabled())
945        return;
946
947    // FIXME: This is lifted directly off SkiaSupport, lines 49-74
948    // so it is not guaranteed to work correctly.
949    size_t dashLength = dashes.size();
950    if (!dashLength) {
951        // If no dash is set, revert to solid stroke
952        // FIXME: do we need to set NoStroke in some cases?
953        platformContext()->setStrokeStyle(SolidStroke);
954        platformContext()->setDashPathEffect(0);
955        return;
956    }
957
958    size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
959    SkScalar* intervals = new SkScalar[count];
960
961    for (unsigned int i = 0; i < count; i++)
962        intervals[i] = dashes[i % dashLength];
963
964    platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
965
966    delete[] intervals;
967}
968
969void GraphicsContext::setLineJoin(LineJoin join)
970{
971    if (paintingDisabled())
972        return;
973    switch (join) {
974    case MiterJoin:
975        platformContext()->setLineJoin(SkPaint::kMiter_Join);
976        break;
977    case RoundJoin:
978        platformContext()->setLineJoin(SkPaint::kRound_Join);
979        break;
980    case BevelJoin:
981        platformContext()->setLineJoin(SkPaint::kBevel_Join);
982        break;
983    default:
984        ASSERT(0);
985        break;
986    }
987}
988
989void GraphicsContext::setMiterLimit(float limit)
990{
991    if (paintingDisabled())
992        return;
993    platformContext()->setMiterLimit(limit);
994}
995
996void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
997{
998    if (paintingDisabled())
999        return;
1000
1001    if (platformContext()->useGPU())
1002        platformContext()->gpuCanvas()->setFillColor(color, colorSpace);
1003
1004    platformContext()->setFillColor(color.rgb());
1005}
1006
1007void GraphicsContext::setPlatformFillGradient(Gradient* gradient)
1008{
1009    if (paintingDisabled())
1010        return;
1011
1012    platformContext()->setFillShader(gradient->platformGradient());
1013}
1014
1015void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
1016{
1017    if (paintingDisabled())
1018        return;
1019
1020    platformContext()->setFillShader(pattern->platformPattern(getCTM()));
1021}
1022
1023void GraphicsContext::setPlatformShadow(const FloatSize& size,
1024                                        float blurFloat,
1025                                        const Color& color,
1026                                        ColorSpace colorSpace)
1027{
1028    if (paintingDisabled())
1029        return;
1030
1031    if (platformContext()->useGPU()) {
1032        GLES2Canvas* canvas = platformContext()->gpuCanvas();
1033        canvas->setShadowOffset(size);
1034        canvas->setShadowBlur(blurFloat);
1035        canvas->setShadowColor(color, colorSpace);
1036        canvas->setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
1037    }
1038
1039    // Detect when there's no effective shadow and clear the looper.
1040    if (!size.width() && !size.height() && !blurFloat) {
1041        platformContext()->setDrawLooper(0);
1042        return;
1043    }
1044
1045    double width = size.width();
1046    double height = size.height();
1047    double blur = blurFloat;
1048
1049    uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag;
1050    SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode;
1051
1052    if (m_state.shadowsIgnoreTransforms)  {
1053        // Currently only the GraphicsContext associated with the
1054        // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
1055        // Transforms. So with this flag set, we know this state is associated
1056        // with a CanvasRenderingContext.
1057        mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
1058
1059        // CSS wants us to ignore the original's alpha, but Canvas wants us to
1060        // modulate with it. Using shadowsIgnoreTransforms to tell us that we're
1061        // in a Canvas, we change the colormode to kDst_Mode, so we don't overwrite
1062        // it with our layer's (default opaque-black) color.
1063        colorMode = SkXfermode::kDst_Mode;
1064
1065        // CG uses natural orientation for Y axis, but the HTML5 canvas spec
1066        // does not.
1067        // So we now flip the height since it was flipped in
1068        // CanvasRenderingContext in order to work with CG.
1069        height = -height;
1070    }
1071
1072    SkColor c;
1073    if (color.isValid())
1074        c = color.rgb();
1075    else
1076        c = SkColorSetARGB(0xFF/3, 0, 0, 0);    // "std" apple shadow color.
1077
1078    // TODO(tc): Should we have a max value for the blur?  CG clamps at 1000.0
1079    // for perf reasons.
1080
1081    SkLayerDrawLooper* dl = new SkLayerDrawLooper;
1082    SkAutoUnref aur(dl);
1083
1084    // top layer, we just draw unchanged
1085    dl->addLayer();
1086
1087    // lower layer contains our offset, blur, and colorfilter
1088    SkLayerDrawLooper::LayerInfo info;
1089
1090    info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur
1091    info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
1092    info.fColorMode = colorMode;
1093    info.fOffset.set(width, height);
1094    info.fPostTranslate = m_state.shadowsIgnoreTransforms;
1095
1096    SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags);
1097
1098    SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode);
1099
1100    SkPaint* paint = dl->addLayer(info);
1101    SkSafeUnref(paint->setMaskFilter(mf));
1102    SkSafeUnref(paint->setColorFilter(cf));
1103
1104    // dl is now built, just install it
1105    platformContext()->setDrawLooper(dl);
1106}
1107
1108void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
1109{
1110    if (paintingDisabled())
1111        return;
1112
1113    platformContext()->setStrokeColor(strokecolor.rgb());
1114}
1115
1116void GraphicsContext::setPlatformStrokeStyle(StrokeStyle stroke)
1117{
1118    if (paintingDisabled())
1119        return;
1120
1121    platformContext()->setStrokeStyle(stroke);
1122}
1123
1124void GraphicsContext::setPlatformStrokeThickness(float thickness)
1125{
1126    if (paintingDisabled())
1127        return;
1128
1129    platformContext()->setStrokeThickness(thickness);
1130}
1131
1132void GraphicsContext::setPlatformStrokeGradient(Gradient* gradient)
1133{
1134    if (paintingDisabled())
1135        return;
1136
1137    platformContext()->setStrokeShader(gradient->platformGradient());
1138}
1139
1140void GraphicsContext::setPlatformStrokePattern(Pattern* pattern)
1141{
1142    if (paintingDisabled())
1143        return;
1144
1145    platformContext()->setStrokeShader(pattern->platformPattern(getCTM()));
1146}
1147
1148void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
1149{
1150    if (paintingDisabled())
1151        return;
1152
1153    platformContext()->setTextDrawingMode(mode);
1154}
1155
1156void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
1157{
1158}
1159
1160void GraphicsContext::setPlatformShouldAntialias(bool enable)
1161{
1162    if (paintingDisabled())
1163        return;
1164
1165    platformContext()->setUseAntialiasing(enable);
1166}
1167
1168void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
1169{
1170    if (paintingDisabled())
1171        return;
1172
1173    platformContext()->prepareForSoftwareDraw();
1174
1175    SkPaint paint;
1176    SkRect oval = r;
1177    if (strokeStyle() == NoStroke) {
1178        // Stroke using the fill color.
1179        // TODO(brettw) is this really correct? It seems unreasonable.
1180        platformContext()->setupPaintForFilling(&paint);
1181        paint.setStyle(SkPaint::kStroke_Style);
1182        paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
1183    } else
1184        platformContext()->setupPaintForStroking(&paint, 0, 0);
1185
1186    // We do this before converting to scalar, so we don't overflow SkFixed.
1187    startAngle = fastMod(startAngle, 360);
1188    angleSpan = fastMod(angleSpan, 360);
1189
1190    SkPath path;
1191    path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
1192    if (!isPathSkiaSafe(getCTM(), path))
1193        return;
1194    platformContext()->canvas()->drawPath(path, paint);
1195}
1196
1197void GraphicsContext::strokePath(const Path& pathToStroke)
1198{
1199    if (paintingDisabled())
1200        return;
1201
1202    SkPath path = *pathToStroke.platformPath();
1203    if (!isPathSkiaSafe(getCTM(), path))
1204        return;
1205
1206    platformContext()->prepareForSoftwareDraw();
1207
1208    SkPaint paint;
1209    platformContext()->setupPaintForStroking(&paint, 0, 0);
1210    platformContext()->canvas()->drawPath(path, paint);
1211}
1212
1213void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
1214{
1215    if (paintingDisabled())
1216        return;
1217
1218    if (!isRectSkiaSafe(getCTM(), rect))
1219        return;
1220
1221    platformContext()->prepareForSoftwareDraw();
1222
1223    SkPaint paint;
1224    platformContext()->setupPaintForStroking(&paint, 0, 0);
1225    paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
1226    platformContext()->canvas()->drawRect(rect, paint);
1227}
1228
1229void GraphicsContext::rotate(float angleInRadians)
1230{
1231    if (paintingDisabled())
1232        return;
1233
1234    if (platformContext()->useGPU())
1235        platformContext()->gpuCanvas()->rotate(angleInRadians);
1236
1237    platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
1238        angleInRadians * (180.0f / 3.14159265f)));
1239}
1240
1241void GraphicsContext::translate(float w, float h)
1242{
1243    if (paintingDisabled())
1244        return;
1245
1246    if (platformContext()->useGPU())
1247        platformContext()->gpuCanvas()->translate(w, h);
1248
1249    platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
1250                                           WebCoreFloatToSkScalar(h));
1251}
1252
1253void GraphicsContext::syncSoftwareCanvas()
1254{
1255    platformContext()->syncSoftwareCanvas();
1256}
1257
1258void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* framebuffer, const IntSize& size)
1259{
1260    platformContext()->setSharedGraphicsContext3D(context, framebuffer, size);
1261}
1262
1263void GraphicsContext::markDirtyRect(const IntRect& rect)
1264{
1265    platformContext()->markDirtyRect(rect);
1266}
1267
1268}  // namespace WebCore
1269