~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "Gradient.h"
 
38
#include "ImageBuffer.h"
 
39
#include "IntRect.h"
 
40
#include "KURL.h"
 
41
#include "NativeImageSkia.h"
 
42
#include "NotImplemented.h"
 
43
#include "PlatformContextSkia.h"
 
44
 
 
45
#include "SkAnnotation.h"
 
46
#include "SkBitmap.h"
 
47
#include "SkBlurMaskFilter.h"
 
48
#include "SkColorFilter.h"
 
49
#include "SkCornerPathEffect.h"
 
50
#include "SkData.h"
 
51
#include "SkLayerDrawLooper.h"
 
52
#include "SkShader.h"
 
53
#include "SkiaUtils.h"
 
54
#include "skia/ext/platform_canvas.h"
 
55
 
 
56
#include <math.h>
 
57
#include <wtf/Assertions.h>
 
58
#include <wtf/MathExtras.h>
 
59
#include <wtf/UnusedParam.h>
 
60
 
 
61
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
62
#include <ApplicationServices/ApplicationServices.h>
 
63
#endif
 
64
 
 
65
using namespace std;
 
66
 
 
67
namespace WebCore {
 
68
 
 
69
namespace {
 
70
 
 
71
// Return value % max, but account for value possibly being negative.
 
72
inline int fastMod(int value, int max)
 
73
{
 
74
    bool isNeg = false;
 
75
    if (value < 0) {
 
76
        value = -value;
 
77
        isNeg = true;
 
78
    }
 
79
    if (value >= max)
 
80
        value %= max;
 
81
    if (isNeg)
 
82
        value = -value;
 
83
    return value;
 
84
}
 
85
 
 
86
}  // namespace
 
87
 
 
88
// Local helper functions ------------------------------------------------------
 
89
 
 
90
void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
 
91
{
 
92
    SkIRect ir;
 
93
    int rx = SkMin32(SkScalarRound(rect.width()), size.width());
 
94
    int ry = SkMin32(SkScalarRound(rect.height()), size.height());
 
95
 
 
96
    ir.set(-rx, -ry, rx, ry);
 
97
    switch (startAngle) {
 
98
    case 0:
 
99
        ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
 
100
        break;
 
101
    case 90:
 
102
        ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
 
103
        break;
 
104
    case 180:
 
105
        ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
 
106
        break;
 
107
    case 270:
 
108
        ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
 
109
        break;
 
110
    default:
 
111
        ASSERT(0);
 
112
    }
 
113
 
 
114
    SkRect r;
 
115
    r.set(ir);
 
116
    path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
 
117
}
 
118
 
 
119
void draw2xMarker(SkBitmap* bitmap, int index)
 
120
{
 
121
 
 
122
    static const SkPMColor lineColors[2] = {
 
123
        SkPreMultiplyARGB(0xFF, 0xFF, 0x00, 0x00), // Opaque red.
 
124
        SkPreMultiplyARGB(0xFF, 0xC0, 0xC0, 0xC0), // Opaque gray.
 
125
    };
 
126
    static const SkPMColor antiColors1[2] = {
 
127
        SkPreMultiplyARGB(0xB0, 0xFF, 0x00, 0x00), // Semitransparent red
 
128
        SkPreMultiplyARGB(0xB0, 0xC0, 0xC0, 0xC0), // Semitransparent gray
 
129
    };
 
130
    static const SkPMColor antiColors2[2] = {
 
131
        SkPreMultiplyARGB(0x60, 0xFF, 0x00, 0x00), // More transparent red
 
132
        SkPreMultiplyARGB(0x60, 0xC0, 0xC0, 0xC0), // More transparent gray
 
133
    };
 
134
 
 
135
    const SkPMColor lineColor = lineColors[index];
 
136
    const SkPMColor antiColor1 = antiColors1[index];
 
137
    const SkPMColor antiColor2 = antiColors2[index];
 
138
 
 
139
    uint32_t* row1 = bitmap->getAddr32(0, 0);
 
140
    uint32_t* row2 = bitmap->getAddr32(0, 1);
 
141
    uint32_t* row3 = bitmap->getAddr32(0, 2);
 
142
    uint32_t* row4 = bitmap->getAddr32(0, 3);
 
143
 
 
144
    // Pattern: X0o   o0X0o   o0
 
145
    //          XX0o o0XXX0o o0X
 
146
    //           o0XXX0o o0XXX0o
 
147
    //            o0X0o   o0X0o
 
148
    const SkPMColor row1Color[] = { lineColor, antiColor1, antiColor2, 0,          0,         0,          antiColor2, antiColor1 };
 
149
    const SkPMColor row2Color[] = { lineColor, lineColor,  antiColor1, antiColor2, 0,         antiColor2, antiColor1, lineColor };
 
150
    const SkPMColor row3Color[] = { 0,         antiColor2, antiColor1, lineColor,  lineColor, lineColor,  antiColor1, antiColor2 };
 
151
    const SkPMColor row4Color[] = { 0,         0,          antiColor2, antiColor1, lineColor, antiColor1, antiColor2, 0 };
 
152
 
 
153
    for (int x = 0; x < bitmap->width() + 8; x += 8) {
 
154
        int count = min(bitmap->width() - x, 8);
 
155
        if (count > 0) {
 
156
            memcpy(row1 + x, row1Color, count * sizeof(SkPMColor));
 
157
            memcpy(row2 + x, row2Color, count * sizeof(SkPMColor));
 
158
            memcpy(row3 + x, row3Color, count * sizeof(SkPMColor));
 
159
            memcpy(row4 + x, row4Color, count * sizeof(SkPMColor));
 
160
        }
 
161
    }
 
162
}
 
163
 
 
164
void draw1xMarker(SkBitmap* bitmap, int index)
 
165
{
 
166
    static const uint32_t lineColors[2] = {
 
167
        0xFF << SK_A32_SHIFT | 0xFF << SK_R32_SHIFT, // Opaque red.
 
168
        0xFF << SK_A32_SHIFT | 0xC0 << SK_R32_SHIFT | 0xC0 << SK_G32_SHIFT | 0xC0 << SK_B32_SHIFT, // Opaque gray.
 
169
    };
 
170
    static const uint32_t antiColors[2] = {
 
171
        0x60 << SK_A32_SHIFT | 0x60 << SK_R32_SHIFT, // Semitransparent red
 
172
        0xFF << SK_A32_SHIFT | 0xC0 << SK_R32_SHIFT | 0xC0 << SK_G32_SHIFT | 0xC0 << SK_B32_SHIFT, // Semitransparent gray
 
173
    };
 
174
 
 
175
    const uint32_t lineColor = lineColors[index];
 
176
    const uint32_t antiColor = antiColors[index];
 
177
 
 
178
    // Pattern: X o   o X o   o X
 
179
    //            o X o   o X o
 
180
    uint32_t* row1 = bitmap->getAddr32(0, 0);
 
181
    uint32_t* row2 = bitmap->getAddr32(0, 1);
 
182
    for (int x = 0; x < bitmap->width(); x++) {
 
183
        switch (x % 4) {
 
184
        case 0:
 
185
            row1[x] = lineColor;
 
186
            break;
 
187
        case 1:
 
188
            row1[x] = antiColor;
 
189
            row2[x] = antiColor;
 
190
            break;
 
191
        case 2:
 
192
            row2[x] = lineColor;
 
193
            break;
 
194
        case 3:
 
195
            row1[x] = antiColor;
 
196
            row2[x] = antiColor;
 
197
            break;
 
198
        }
 
199
    }
 
200
}
 
201
 
 
202
// -----------------------------------------------------------------------------
 
203
 
 
204
// This may be called with a NULL pointer to create a graphics context that has
 
205
// no painting.
 
206
void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
 
207
{
 
208
    if (gc)
 
209
        gc->setGraphicsContext(this);
 
210
 
 
211
    // the caller owns the gc
 
212
    m_data = gc;
 
213
    setPaintingDisabled(!gc || !gc->canvas());
 
214
}
 
215
 
 
216
void GraphicsContext::platformDestroy()
 
217
{
 
218
}
 
219
 
 
220
PlatformGraphicsContext* GraphicsContext::platformContext() const
 
221
{
 
222
    ASSERT(!paintingDisabled());
 
223
    return m_data;
 
224
}
 
225
 
 
226
// State saving ----------------------------------------------------------------
 
227
 
 
228
void GraphicsContext::savePlatformState()
 
229
{
 
230
    if (paintingDisabled())
 
231
        return;
 
232
 
 
233
    // Save our private State.
 
234
    platformContext()->save();
 
235
}
 
236
 
 
237
void GraphicsContext::restorePlatformState()
 
238
{
 
239
    if (paintingDisabled())
 
240
        return;
 
241
 
 
242
    // Restore our private State.
 
243
    platformContext()->restore();
 
244
}
 
245
 
 
246
void GraphicsContext::beginPlatformTransparencyLayer(float opacity)
 
247
{
 
248
    if (paintingDisabled())
 
249
        return;
 
250
 
 
251
    // We need the "alpha" layer flag here because the base layer is opaque
 
252
    // (the surface of the page) but layers on top may have transparent parts.
 
253
    // Without explicitly setting the alpha flag, the layer will inherit the
 
254
    // opaque setting of the base and some things won't work properly.
 
255
    SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
 
256
 
 
257
    SkPaint layerPaint;
 
258
    layerPaint.setAlpha(static_cast<unsigned char>(opacity * 255));
 
259
    layerPaint.setXfermodeMode(platformContext()->getXfermodeMode());
 
260
 
 
261
    platformContext()->saveLayer(0, &layerPaint, saveFlags);
 
262
}
 
263
 
 
264
void GraphicsContext::endPlatformTransparencyLayer()
 
265
{
 
266
    if (paintingDisabled())
 
267
        return;
 
268
    platformContext()->restoreLayer();
 
269
}
 
270
 
 
271
bool GraphicsContext::supportsTransparencyLayers()
 
272
{
 
273
    return true;
 
274
}
 
275
 
 
276
// Graphics primitives ---------------------------------------------------------
 
277
 
 
278
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
 
279
{
 
280
    if (paintingDisabled())
 
281
        return;
 
282
 
 
283
    SkRect r(rect);
 
284
    SkPath path;
 
285
    path.addOval(r, SkPath::kCW_Direction);
 
286
    // only perform the inset if we won't invert r
 
287
    if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
 
288
        // Adding one to the thickness doesn't make the border too thick as
 
289
        // it's painted over afterwards. But without this adjustment the
 
290
        // border appears a little anemic after anti-aliasing.
 
291
        r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
 
292
        path.addOval(r, SkPath::kCCW_Direction);
 
293
    }
 
294
    platformContext()->clipPath(path, PlatformContextSkia::AntiAliased);
 
295
}
 
296
 
 
297
void GraphicsContext::clearPlatformShadow()
 
298
{
 
299
    if (paintingDisabled())
 
300
        return;
 
301
    platformContext()->setDrawLooper(0);
 
302
}
 
303
 
 
304
void GraphicsContext::clearRect(const FloatRect& rect)
 
305
{
 
306
    if (paintingDisabled())
 
307
        return;
 
308
 
 
309
    SkRect r = rect;
 
310
    SkPaint paint;
 
311
    platformContext()->setupPaintForFilling(&paint);
 
312
    paint.setXfermodeMode(SkXfermode::kClear_Mode);
 
313
    platformContext()->drawRect(r, paint);
 
314
}
 
315
 
 
316
void GraphicsContext::clip(const FloatRect& rect)
 
317
{
 
318
    if (paintingDisabled())
 
319
        return;
 
320
 
 
321
    platformContext()->clipRect(rect);
 
322
}
 
323
 
 
324
void GraphicsContext::clip(const Path& path)
 
325
{
 
326
    if (paintingDisabled() || path.isEmpty())
 
327
        return;
 
328
 
 
329
    platformContext()->clipPath(*path.platformPath(), PlatformContextSkia::AntiAliased);
 
330
}
 
331
 
 
332
void GraphicsContext::canvasClip(const Path& path)
 
333
{
 
334
    if (paintingDisabled())
 
335
        return;
 
336
 
 
337
    platformContext()->canvasClipPath(path.isNull() ? SkPath() : *path.platformPath());
 
338
}
 
339
 
 
340
void GraphicsContext::clipOut(const IntRect& rect)
 
341
{
 
342
    if (paintingDisabled())
 
343
        return;
 
344
 
 
345
    platformContext()->clipRect(rect, PlatformContextSkia::NotAntiAliased, SkRegion::kDifference_Op);
 
346
}
 
347
 
 
348
void GraphicsContext::clipOut(const Path& p)
 
349
{
 
350
    if (paintingDisabled())
 
351
        return;
 
352
 
 
353
    // We must make a copy of the path, to mark it as inverse-filled.
 
354
    SkPath path(p.isNull() ? SkPath() : *p.platformPath());
 
355
    path.toggleInverseFillType();
 
356
    platformContext()->clipPath(path, PlatformContextSkia::AntiAliased);
 
357
}
 
358
 
 
359
void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
 
360
{
 
361
    if (paintingDisabled())
 
362
        return;
 
363
 
 
364
    const SkPath* path = pathToClip.platformPath();
 
365
    SkPath::FillType ftype = (clipRule == RULE_EVENODD) ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
 
366
    SkPath storage;
 
367
    if (!path)
 
368
        path = &storage;
 
369
    else if (path->getFillType() != ftype) {
 
370
        storage = *path;
 
371
        storage.setFillType(ftype);
 
372
        path = &storage;
 
373
    }
 
374
    platformContext()->clipPath(*path, PlatformContextSkia::AntiAliased);
 
375
}
 
376
 
 
377
void GraphicsContext::concatCTM(const AffineTransform& affine)
 
378
{
 
379
    if (paintingDisabled())
 
380
        return;
 
381
 
 
382
    platformContext()->concat(affine);
 
383
}
 
384
 
 
385
void GraphicsContext::setCTM(const AffineTransform& affine)
 
386
{
 
387
    if (paintingDisabled())
 
388
        return;
 
389
 
 
390
    platformContext()->setMatrix(affine);
 
391
}
 
392
 
 
393
static void setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points)
 
394
{
 
395
    path->incReserve(numPoints);
 
396
    path->moveTo(WebCoreFloatToSkScalar(points[0].x()),
 
397
                 WebCoreFloatToSkScalar(points[0].y()));
 
398
    for (size_t i = 1; i < numPoints; ++i) {
 
399
        path->lineTo(WebCoreFloatToSkScalar(points[i].x()),
 
400
                     WebCoreFloatToSkScalar(points[i].y()));
 
401
    }
 
402
 
 
403
    /*  The code used to just blindly call this
 
404
            path->setIsConvex(true);
 
405
        But webkit can sometimes send us non-convex 4-point values, so we mark the path's
 
406
        convexity as unknown, so it will get computed by skia at draw time.
 
407
        See crbug.com 108605
 
408
    */
 
409
    SkPath::Convexity convexity = SkPath::kConvex_Convexity;
 
410
    if (numPoints == 4)
 
411
        convexity = SkPath::kUnknown_Convexity;
 
412
    path->setConvexity(convexity);
 
413
}
 
414
 
 
415
void GraphicsContext::drawConvexPolygon(size_t numPoints,
 
416
                                        const FloatPoint* points,
 
417
                                        bool shouldAntialias)
 
418
{
 
419
    if (paintingDisabled())
 
420
        return;
 
421
 
 
422
    if (numPoints <= 1)
 
423
        return;
 
424
 
 
425
    SkPath path;
 
426
    setPathFromConvexPoints(&path, numPoints, points);
 
427
 
 
428
    SkPaint paint;
 
429
    platformContext()->setupPaintForFilling(&paint);
 
430
    paint.setAntiAlias(shouldAntialias);
 
431
    platformContext()->drawPath(path, paint);
 
432
 
 
433
    if (strokeStyle() != NoStroke) {
 
434
        paint.reset();
 
435
        platformContext()->setupPaintForStroking(&paint, 0, 0);
 
436
        platformContext()->drawPath(path, paint);
 
437
    }
 
438
}
 
439
 
 
440
void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
 
441
{
 
442
    if (paintingDisabled())
 
443
        return;
 
444
 
 
445
    if (numPoints <= 1)
 
446
        return;
 
447
 
 
448
    SkPath path;
 
449
    setPathFromConvexPoints(&path, numPoints, points);
 
450
    platformContext()->clipPath(path, antialiased
 
451
        ? PlatformContextSkia::AntiAliased
 
452
        : PlatformContextSkia::NotAntiAliased);
 
453
}
 
454
 
 
455
// This method is only used to draw the little circles used in lists.
 
456
void GraphicsContext::drawEllipse(const IntRect& elipseRect)
 
457
{
 
458
    if (paintingDisabled())
 
459
        return;
 
460
 
 
461
    SkRect rect = elipseRect;
 
462
    SkPaint paint;
 
463
    platformContext()->setupPaintForFilling(&paint);
 
464
    platformContext()->drawOval(rect, paint);
 
465
 
 
466
    if (strokeStyle() != NoStroke) {
 
467
        paint.reset();
 
468
        platformContext()->setupPaintForStroking(&paint, &rect, 0);
 
469
        platformContext()->drawOval(rect, paint);
 
470
    }
 
471
}
 
472
 
 
473
void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
 
474
{
 
475
    // FIXME: implement
 
476
}
 
477
 
 
478
static inline void drawOuterPath(PlatformContextSkia* context, const SkPath& path, SkPaint& paint, int width)
 
479
{
 
480
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
481
    paint.setAlpha(64);
 
482
    paint.setStrokeWidth(width);
 
483
    paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref();
 
484
#else
 
485
    paint.setStrokeWidth(1);
 
486
    paint.setPathEffect(new SkCornerPathEffect(1))->unref();
 
487
#endif
 
488
    context->drawPath(path, paint);
 
489
}
 
490
 
 
491
static inline void drawInnerPath(PlatformContextSkia* context, const SkPath& path, SkPaint& paint, int width)
 
492
{
 
493
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
494
    paint.setAlpha(128);
 
495
    paint.setStrokeWidth(width * 0.5f);
 
496
    context->drawPath(path, paint);
 
497
#endif
 
498
}
 
499
 
 
500
static inline int getFocusRingOutset(int offset)
 
501
{
 
502
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
503
    return offset + 2;
 
504
#else
 
505
    return 0;
 
506
#endif
 
507
}
 
508
 
 
509
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
 
510
{
 
511
    if (paintingDisabled())
 
512
        return;
 
513
 
 
514
    unsigned rectCount = rects.size();
 
515
    if (!rectCount)
 
516
        return;
 
517
 
 
518
    SkRegion focusRingRegion;
 
519
    const int focusRingOutset = getFocusRingOutset(offset);
 
520
    for (unsigned i = 0; i < rectCount; i++) {
 
521
        SkIRect r = rects[i];
 
522
        r.inset(-focusRingOutset, -focusRingOutset);
 
523
        focusRingRegion.op(r, SkRegion::kUnion_Op);
 
524
    }
 
525
 
 
526
    SkPath path;
 
527
    SkPaint paint;
 
528
    paint.setAntiAlias(true);
 
529
    paint.setStyle(SkPaint::kStroke_Style);
 
530
 
 
531
    paint.setColor(color.rgb());
 
532
    focusRingRegion.getBoundaryPath(&path);
 
533
    drawOuterPath(platformContext(), path, paint, width);
 
534
    drawInnerPath(platformContext(), path, paint, width);
 
535
}
 
536
 
 
537
// This is only used to draw borders.
 
538
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
 
539
{
 
540
    if (paintingDisabled())
 
541
        return;
 
542
 
 
543
    StrokeStyle penStyle = strokeStyle();
 
544
    if (penStyle == NoStroke)
 
545
        return;
 
546
 
 
547
    SkPaint paint;
 
548
    FloatPoint p1 = point1;
 
549
    FloatPoint p2 = point2;
 
550
    bool isVerticalLine = (p1.x() == p2.x());
 
551
    int width = roundf(strokeThickness());
 
552
 
 
553
    // We know these are vertical or horizontal lines, so the length will just
 
554
    // be the sum of the displacement component vectors give or take 1 -
 
555
    // probably worth the speed up of no square root, which also won't be exact.
 
556
    FloatSize disp = p2 - p1;
 
557
    int length = SkScalarRound(disp.width() + disp.height());
 
558
    platformContext()->setupPaintForStroking(&paint, 0, length);
 
559
 
 
560
    if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
 
561
        // Do a rect fill of our endpoints.  This ensures we always have the
 
562
        // appearance of being a border.  We then draw the actual dotted/dashed line.
 
563
 
 
564
        SkRect r1, r2;
 
565
        r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
 
566
        r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
 
567
 
 
568
        if (isVerticalLine) {
 
569
            r1.offset(-width / 2, 0);
 
570
            r2.offset(-width / 2, -width);
 
571
        } else {
 
572
            r1.offset(0, -width / 2);
 
573
            r2.offset(-width, -width / 2);
 
574
        }
 
575
        SkPaint fillPaint;
 
576
        fillPaint.setColor(paint.getColor());
 
577
        platformContext()->drawRect(r1, fillPaint);
 
578
        platformContext()->drawRect(r2, fillPaint);
 
579
    }
 
580
 
 
581
    adjustLineToPixelBoundaries(p1, p2, width, penStyle);
 
582
    SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
 
583
 
 
584
    platformContext()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
 
585
}
 
586
 
 
587
void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float width, DocumentMarkerLineStyle style)
 
588
{
 
589
    if (paintingDisabled())
 
590
        return;
 
591
 
 
592
    int deviceScaleFactor = SkScalarRoundToInt(WebCoreFloatToSkScalar(platformContext()->deviceScaleFactor()));
 
593
    ASSERT(deviceScaleFactor == 1 || deviceScaleFactor == 2);
 
594
 
 
595
    // Create the pattern we'll use to draw the underline.
 
596
    int index = style == DocumentMarkerGrammarLineStyle ? 1 : 0;
 
597
    static SkBitmap* misspellBitmap1x[2] = { 0, 0 };
 
598
    static SkBitmap* misspellBitmap2x[2] = { 0, 0 };
 
599
    SkBitmap** misspellBitmap = deviceScaleFactor == 2 ? misspellBitmap2x : misspellBitmap1x;
 
600
    if (!misspellBitmap[index]) {
 
601
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
602
        // Match the artwork used by the Mac.
 
603
        const int rowPixels = 4 * deviceScaleFactor;
 
604
        const int colPixels = 3 * deviceScaleFactor;
 
605
        misspellBitmap[index] = new SkBitmap;
 
606
        misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config,
 
607
                                         rowPixels, colPixels);
 
608
        misspellBitmap[index]->allocPixels();
 
609
 
 
610
        misspellBitmap[index]->eraseARGB(0, 0, 0, 0);
 
611
        const uint32_t transparentColor = 0x00000000;
 
612
 
 
613
        if (deviceScaleFactor == 1) {
 
614
            const uint32_t colors[2][6] = {
 
615
                { 0x2A2A0600, 0x57571000,  0xA8A81B00, 0xBFBF1F00,  0x70701200, 0xE0E02400 },
 
616
                { 0x2A001503, 0x57002A08,  0xA800540D, 0xBF005F0F,  0x70003809, 0xE0007012 }
 
617
            };
 
618
 
 
619
            // Pattern: a b a   a b a
 
620
            //          c d c   c d c
 
621
            //          e f e   e f e
 
622
            for (int x = 0; x < colPixels; ++x) {
 
623
                uint32_t* row = misspellBitmap[index]->getAddr32(0, x);
 
624
                row[0] = colors[index][x * 2];
 
625
                row[1] = colors[index][x * 2 + 1];
 
626
                row[2] = colors[index][x * 2];
 
627
                row[3] = transparentColor;
 
628
            }
 
629
        } else if (deviceScaleFactor == 2) {
 
630
            const uint32_t colors[2][18] = {
 
631
                { 0x0a090101, 0x33320806, 0x55540f0a,  0x37360906, 0x6e6c120c, 0x6e6c120c,  0x7674140d, 0x8d8b1810, 0x8d8b1810,
 
632
                  0x96941a11, 0xb3b01f15, 0xb3b01f15,  0x6d6b130c, 0xd9d62619, 0xd9d62619,  0x19180402, 0x7c7a150e, 0xcecb2418 },
 
633
                { 0x0a000400, 0x33031b06, 0x55062f0b,  0x37041e06, 0x6e083d0d, 0x6e083d0d,  0x7608410e, 0x8d094e11, 0x8d094e11,
 
634
                  0x960a5313, 0xb30d6417, 0xb30d6417,  0x6d073c0d, 0xd90f781c, 0xd90f781c,  0x19010d03, 0x7c094510, 0xce0f731a }
 
635
            };
 
636
 
 
637
            // Pattern: a b c c b a
 
638
            //          d e f f e d
 
639
            //          g h j j h g
 
640
            //          k l m m l k
 
641
            //          n o p p o n
 
642
            //          q r s s r q
 
643
            for (int x = 0; x < colPixels; ++x) {
 
644
                uint32_t* row = misspellBitmap[index]->getAddr32(0, x);
 
645
                row[0] = colors[index][x * 3];
 
646
                row[1] = colors[index][x * 3 + 1];
 
647
                row[2] = colors[index][x * 3 + 2];
 
648
                row[3] = colors[index][x * 3 + 2];
 
649
                row[4] = colors[index][x * 3 + 1];
 
650
                row[5] = colors[index][x * 3];
 
651
                row[6] = transparentColor;
 
652
                row[7] = transparentColor;
 
653
            }
 
654
        } else
 
655
            ASSERT_NOT_REACHED();
 
656
#else
 
657
        // We use a 2-pixel-high misspelling indicator because that seems to be
 
658
        // what WebKit is designed for, and how much room there is in a typical
 
659
        // page for it.
 
660
        const int rowPixels = 32 * deviceScaleFactor; // Must be multiple of 4 for pattern below.
 
661
        const int colPixels = 2 * deviceScaleFactor;
 
662
        misspellBitmap[index] = new SkBitmap;
 
663
        misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels);
 
664
        misspellBitmap[index]->allocPixels();
 
665
 
 
666
        misspellBitmap[index]->eraseARGB(0, 0, 0, 0);
 
667
        if (deviceScaleFactor == 1)
 
668
            draw1xMarker(misspellBitmap[index], index);
 
669
        else if (deviceScaleFactor == 2)
 
670
            draw2xMarker(misspellBitmap[index], index);
 
671
        else
 
672
            ASSERT_NOT_REACHED();
 
673
#endif
 
674
    }
 
675
 
 
676
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
677
    SkScalar originX = WebCoreFloatToSkScalar(pt.x()) * deviceScaleFactor;
 
678
    SkScalar originY = WebCoreFloatToSkScalar(pt.y()) * deviceScaleFactor;
 
679
 
 
680
    // Make sure to draw only complete dots.
 
681
    int rowPixels = misspellBitmap[index]->width();
 
682
    float widthMod = fmodf(width * deviceScaleFactor, rowPixels);
 
683
    if (rowPixels - widthMod > deviceScaleFactor)
 
684
        width -= widthMod / deviceScaleFactor;
 
685
#else
 
686
    SkScalar originX = WebCoreFloatToSkScalar(pt.x());
 
687
 
 
688
    // Offset it vertically by 1 so that there's some space under the text.
 
689
    SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
 
690
    originX *= deviceScaleFactor;
 
691
    originY *= deviceScaleFactor;
 
692
#endif
 
693
 
 
694
    // Make a shader for the bitmap with an origin of the box we'll draw. This
 
695
    // shader is refcounted and will have an initial refcount of 1.
 
696
    SkShader* shader = SkShader::CreateBitmapShader(
 
697
        *misspellBitmap[index], SkShader::kRepeat_TileMode,
 
698
        SkShader::kRepeat_TileMode);
 
699
    SkMatrix matrix;
 
700
    matrix.setTranslate(originX, originY);
 
701
    shader->setLocalMatrix(matrix);
 
702
 
 
703
    // Assign the shader to the paint & release our reference. The paint will
 
704
    // now own the shader and the shader will be destroyed when the paint goes
 
705
    // out of scope.
 
706
    SkPaint paint;
 
707
    paint.setShader(shader)->unref();
 
708
 
 
709
    SkRect rect;
 
710
    rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width) * deviceScaleFactor, originY + SkIntToScalar(misspellBitmap[index]->height()));
 
711
 
 
712
    if (deviceScaleFactor == 2) {
 
713
        platformContext()->save();
 
714
        platformContext()->scale(SK_ScalarHalf, SK_ScalarHalf);
 
715
    }
 
716
    platformContext()->drawRect(rect, paint);
 
717
    if (deviceScaleFactor == 2)
 
718
        platformContext()->restore();
 
719
}
 
720
 
 
721
void GraphicsContext::drawLineForText(const FloatPoint& pt,
 
722
                                      float width,
 
723
                                      bool printing)
 
724
{
 
725
    if (paintingDisabled())
 
726
        return;
 
727
 
 
728
    if (width <= 0)
 
729
        return;
 
730
 
 
731
    int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
 
732
    SkRect r;
 
733
    r.fLeft = WebCoreFloatToSkScalar(pt.x());
 
734
    // Avoid anti-aliasing lines. Currently, these are always horizontal.
 
735
    r.fTop = WebCoreFloatToSkScalar(floorf(pt.y()));
 
736
    r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
 
737
    r.fBottom = r.fTop + SkIntToScalar(thickness);
 
738
 
 
739
    SkPaint paint;
 
740
    platformContext()->setupPaintForFilling(&paint);
 
741
    // Text lines are drawn using the stroke color.
 
742
    paint.setColor(platformContext()->effectiveStrokeColor());
 
743
    platformContext()->drawRect(r, paint);
 
744
}
 
745
 
 
746
// Draws a filled rectangle with a stroked border.
 
747
void GraphicsContext::drawRect(const IntRect& rect)
 
748
{
 
749
    if (paintingDisabled())
 
750
        return;
 
751
 
 
752
    ASSERT(!rect.isEmpty());
 
753
    if (rect.isEmpty())
 
754
        return;
 
755
 
 
756
    platformContext()->drawRect(rect);
 
757
}
 
758
 
 
759
void GraphicsContext::fillPath(const Path& pathToFill)
 
760
{
 
761
    if (paintingDisabled() || pathToFill.isEmpty())
 
762
        return;
 
763
 
 
764
    const GraphicsContextState& state = m_state;
 
765
    SkPath::FillType ftype = state.fillRule == RULE_EVENODD ?
 
766
        SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
 
767
 
 
768
    const SkPath* path = pathToFill.platformPath();
 
769
    SkPath storage;
 
770
    if (path->getFillType() != ftype) {
 
771
        storage = *path;
 
772
        storage.setFillType(ftype);
 
773
        path = &storage;
 
774
    }
 
775
 
 
776
    SkPaint paint;
 
777
    platformContext()->setupPaintForFilling(&paint);
 
778
 
 
779
    platformContext()->drawPath(*path, paint);
 
780
}
 
781
 
 
782
void GraphicsContext::fillRect(const FloatRect& rect)
 
783
{
 
784
    if (paintingDisabled())
 
785
        return;
 
786
 
 
787
    SkRect r = rect;
 
788
 
 
789
    SkPaint paint;
 
790
    platformContext()->setupPaintForFilling(&paint);
 
791
    platformContext()->drawRect(r, paint);
 
792
}
 
793
 
 
794
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
 
795
{
 
796
    if (paintingDisabled())
 
797
        return;
 
798
 
 
799
    SkRect r = rect;
 
800
    SkPaint paint;
 
801
    platformContext()->setupPaintCommon(&paint);
 
802
    paint.setColor(color.rgb());
 
803
    platformContext()->drawRect(r, paint);
 
804
}
 
805
 
 
806
void GraphicsContext::fillRoundedRect(const IntRect& rect,
 
807
                                      const IntSize& topLeft,
 
808
                                      const IntSize& topRight,
 
809
                                      const IntSize& bottomLeft,
 
810
                                      const IntSize& bottomRight,
 
811
                                      const Color& color,
 
812
                                      ColorSpace colorSpace)
 
813
{
 
814
    if (paintingDisabled())
 
815
        return;
 
816
 
 
817
    if (topLeft.width() + topRight.width() > rect.width()
 
818
            || bottomLeft.width() + bottomRight.width() > rect.width()
 
819
            || topLeft.height() + bottomLeft.height() > rect.height()
 
820
            || topRight.height() + bottomRight.height() > rect.height()) {
 
821
        // Not all the radii fit, return a rect. This matches the behavior of
 
822
        // Path::createRoundedRectangle. Without this we attempt to draw a round
 
823
        // shadow for a square box.
 
824
        fillRect(rect, color, colorSpace);
 
825
        return;
 
826
    }
 
827
 
 
828
    SkRect r = rect;
 
829
    SkPath path;
 
830
    addCornerArc(&path, r, topRight, 270);
 
831
    addCornerArc(&path, r, bottomRight, 0);
 
832
    addCornerArc(&path, r, bottomLeft, 90);
 
833
    addCornerArc(&path, r, topLeft, 180);
 
834
 
 
835
    SkPaint paint;
 
836
    platformContext()->setupPaintForFilling(&paint);
 
837
    paint.setColor(color.rgb());
 
838
    platformContext()->drawPath(path, paint);
 
839
}
 
840
 
 
841
AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
 
842
{
 
843
    if (paintingDisabled())
 
844
        return AffineTransform();
 
845
 
 
846
    const SkMatrix& m = platformContext()->getTotalMatrix();
 
847
    return AffineTransform(SkScalarToDouble(m.getScaleX()),
 
848
                           SkScalarToDouble(m.getSkewY()),
 
849
                           SkScalarToDouble(m.getSkewX()),
 
850
                           SkScalarToDouble(m.getScaleY()),
 
851
                           SkScalarToDouble(m.getTranslateX()),
 
852
                           SkScalarToDouble(m.getTranslateY()));
 
853
}
 
854
 
 
855
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode)
 
856
{
 
857
    return rect;
 
858
}
 
859
 
 
860
void GraphicsContext::scale(const FloatSize& size)
 
861
{
 
862
    if (paintingDisabled())
 
863
        return;
 
864
 
 
865
    platformContext()->scale(WebCoreFloatToSkScalar(size.width()),
 
866
        WebCoreFloatToSkScalar(size.height()));
 
867
}
 
868
 
 
869
void GraphicsContext::setAlpha(float alpha)
 
870
{
 
871
    if (paintingDisabled())
 
872
        return;
 
873
 
 
874
    platformContext()->setAlpha(alpha);
 
875
}
 
876
 
 
877
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
 
878
{
 
879
    if (paintingDisabled())
 
880
        return;
 
881
 
 
882
    platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
 
883
}
 
884
 
 
885
InterpolationQuality GraphicsContext::imageInterpolationQuality() const
 
886
{
 
887
    return platformContext()->interpolationQuality();
 
888
}
 
889
 
 
890
void GraphicsContext::setImageInterpolationQuality(InterpolationQuality q)
 
891
{
 
892
    platformContext()->setInterpolationQuality(q);
 
893
}
 
894
 
 
895
void GraphicsContext::setLineCap(LineCap cap)
 
896
{
 
897
    if (paintingDisabled())
 
898
        return;
 
899
    switch (cap) {
 
900
    case ButtCap:
 
901
        platformContext()->setLineCap(SkPaint::kButt_Cap);
 
902
        break;
 
903
    case RoundCap:
 
904
        platformContext()->setLineCap(SkPaint::kRound_Cap);
 
905
        break;
 
906
    case SquareCap:
 
907
        platformContext()->setLineCap(SkPaint::kSquare_Cap);
 
908
        break;
 
909
    default:
 
910
        ASSERT(0);
 
911
        break;
 
912
    }
 
913
}
 
914
 
 
915
void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
 
916
{
 
917
    if (paintingDisabled())
 
918
        return;
 
919
 
 
920
    // FIXME: This is lifted directly off SkiaSupport, lines 49-74
 
921
    // so it is not guaranteed to work correctly.
 
922
    size_t dashLength = dashes.size();
 
923
    if (!dashLength) {
 
924
        // If no dash is set, revert to solid stroke
 
925
        // FIXME: do we need to set NoStroke in some cases?
 
926
        platformContext()->setStrokeStyle(SolidStroke);
 
927
        platformContext()->setDashPathEffect(0);
 
928
        return;
 
929
    }
 
930
 
 
931
    size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
 
932
    SkScalar* intervals = new SkScalar[count];
 
933
 
 
934
    for (unsigned int i = 0; i < count; i++)
 
935
        intervals[i] = dashes[i % dashLength];
 
936
 
 
937
    platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
 
938
 
 
939
    delete[] intervals;
 
940
}
 
941
 
 
942
void GraphicsContext::setLineJoin(LineJoin join)
 
943
{
 
944
    if (paintingDisabled())
 
945
        return;
 
946
    switch (join) {
 
947
    case MiterJoin:
 
948
        platformContext()->setLineJoin(SkPaint::kMiter_Join);
 
949
        break;
 
950
    case RoundJoin:
 
951
        platformContext()->setLineJoin(SkPaint::kRound_Join);
 
952
        break;
 
953
    case BevelJoin:
 
954
        platformContext()->setLineJoin(SkPaint::kBevel_Join);
 
955
        break;
 
956
    default:
 
957
        ASSERT(0);
 
958
        break;
 
959
    }
 
960
}
 
961
 
 
962
void GraphicsContext::setMiterLimit(float limit)
 
963
{
 
964
    if (paintingDisabled())
 
965
        return;
 
966
    platformContext()->setMiterLimit(limit);
 
967
}
 
968
 
 
969
void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
 
970
{
 
971
    if (paintingDisabled())
 
972
        return;
 
973
 
 
974
    platformContext()->setFillColor(color.rgb());
 
975
}
 
976
 
 
977
void GraphicsContext::setPlatformShadow(const FloatSize& size,
 
978
                                        float blurFloat,
 
979
                                        const Color& color,
 
980
                                        ColorSpace colorSpace)
 
981
{
 
982
    if (paintingDisabled())
 
983
        return;
 
984
 
 
985
    // Detect when there's no effective shadow and clear the looper.
 
986
    if (!size.width() && !size.height() && !blurFloat) {
 
987
        platformContext()->setDrawLooper(0);
 
988
        return;
 
989
    }
 
990
 
 
991
    double width = size.width();
 
992
    double height = size.height();
 
993
    double blur = blurFloat;
 
994
 
 
995
    uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag;
 
996
    SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode;
 
997
 
 
998
    if (m_state.shadowsIgnoreTransforms)  {
 
999
        // Currently only the GraphicsContext associated with the
 
1000
        // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
 
1001
        // Transforms. So with this flag set, we know this state is associated
 
1002
        // with a CanvasRenderingContext.
 
1003
        mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
 
1004
 
 
1005
        // CSS wants us to ignore the original's alpha, but Canvas wants us to
 
1006
        // modulate with it. Using shadowsIgnoreTransforms to tell us that we're
 
1007
        // in a Canvas, we change the colormode to kDst_Mode, so we don't overwrite
 
1008
        // it with our layer's (default opaque-black) color.
 
1009
        colorMode = SkXfermode::kDst_Mode;
 
1010
 
 
1011
        // CG uses natural orientation for Y axis, but the HTML5 canvas spec
 
1012
        // does not.
 
1013
        // So we now flip the height since it was flipped in
 
1014
        // CanvasRenderingContext in order to work with CG.
 
1015
        height = -height;
 
1016
    }
 
1017
 
 
1018
    SkColor c;
 
1019
    if (color.isValid())
 
1020
        c = color.rgb();
 
1021
    else
 
1022
        c = SkColorSetARGB(0xFF/3, 0, 0, 0);    // "std" apple shadow color.
 
1023
 
 
1024
    // TODO(tc): Should we have a max value for the blur?  CG clamps at 1000.0
 
1025
    // for perf reasons.
 
1026
 
 
1027
    SkLayerDrawLooper* dl = new SkLayerDrawLooper;
 
1028
    SkAutoUnref aur(dl);
 
1029
 
 
1030
    // top layer, we just draw unchanged
 
1031
    dl->addLayer();
 
1032
 
 
1033
    // lower layer contains our offset, blur, and colorfilter
 
1034
    SkLayerDrawLooper::LayerInfo info;
 
1035
 
 
1036
    info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur
 
1037
    info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
 
1038
    info.fColorMode = colorMode;
 
1039
    info.fOffset.set(width, height);
 
1040
    info.fPostTranslate = m_state.shadowsIgnoreTransforms;
 
1041
 
 
1042
    SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags);
 
1043
 
 
1044
    SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode);
 
1045
 
 
1046
    SkPaint* paint = dl->addLayer(info);
 
1047
    SkSafeUnref(paint->setMaskFilter(mf));
 
1048
    SkSafeUnref(paint->setColorFilter(cf));
 
1049
 
 
1050
    // dl is now built, just install it
 
1051
    platformContext()->setDrawLooper(dl);
 
1052
}
 
1053
 
 
1054
void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
 
1055
{
 
1056
    if (paintingDisabled())
 
1057
        return;
 
1058
 
 
1059
    platformContext()->setStrokeColor(strokecolor.rgb());
 
1060
}
 
1061
 
 
1062
void GraphicsContext::setPlatformStrokeStyle(StrokeStyle stroke)
 
1063
{
 
1064
    if (paintingDisabled())
 
1065
        return;
 
1066
 
 
1067
    platformContext()->setStrokeStyle(stroke);
 
1068
}
 
1069
 
 
1070
void GraphicsContext::setPlatformStrokeThickness(float thickness)
 
1071
{
 
1072
    if (paintingDisabled())
 
1073
        return;
 
1074
 
 
1075
    platformContext()->setStrokeThickness(thickness);
 
1076
}
 
1077
 
 
1078
void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
 
1079
{
 
1080
    if (paintingDisabled())
 
1081
        return;
 
1082
 
 
1083
    platformContext()->setTextDrawingMode(mode);
 
1084
}
 
1085
 
 
1086
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
 
1087
{
 
1088
    if (paintingDisabled())
 
1089
        return;
 
1090
 
 
1091
    SkAutoDataUnref url(SkData::NewWithCString(link.string().utf8().data()));
 
1092
    SkAnnotateRectWithURL(platformContext()->canvas(), destRect, url.get());
 
1093
}
 
1094
 
 
1095
void GraphicsContext::setPlatformShouldAntialias(bool enable)
 
1096
{
 
1097
    if (paintingDisabled())
 
1098
        return;
 
1099
 
 
1100
    platformContext()->setUseAntialiasing(enable);
 
1101
}
 
1102
 
 
1103
void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
 
1104
{
 
1105
    if (paintingDisabled())
 
1106
        return;
 
1107
 
 
1108
    SkPaint paint;
 
1109
    SkRect oval = r;
 
1110
    if (strokeStyle() == NoStroke) {
 
1111
        // Stroke using the fill color.
 
1112
        // TODO(brettw) is this really correct? It seems unreasonable.
 
1113
        platformContext()->setupPaintForFilling(&paint);
 
1114
        paint.setStyle(SkPaint::kStroke_Style);
 
1115
        paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
 
1116
    } else
 
1117
        platformContext()->setupPaintForStroking(&paint, 0, 0);
 
1118
 
 
1119
    // We do this before converting to scalar, so we don't overflow SkFixed.
 
1120
    startAngle = fastMod(startAngle, 360);
 
1121
    angleSpan = fastMod(angleSpan, 360);
 
1122
 
 
1123
    SkPath path;
 
1124
    path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
 
1125
    platformContext()->drawPath(path, paint);
 
1126
}
 
1127
 
 
1128
void GraphicsContext::strokePath(const Path& pathToStroke)
 
1129
{
 
1130
    if (paintingDisabled() || pathToStroke.isEmpty())
 
1131
        return;
 
1132
 
 
1133
    const SkPath& path = *pathToStroke.platformPath();
 
1134
    SkPaint paint;
 
1135
    platformContext()->setupPaintForStroking(&paint, 0, 0);
 
1136
    platformContext()->drawPath(path, paint);
 
1137
}
 
1138
 
 
1139
void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
 
1140
{
 
1141
    if (paintingDisabled())
 
1142
        return;
 
1143
 
 
1144
    SkPaint paint;
 
1145
    platformContext()->setupPaintForStroking(&paint, 0, 0);
 
1146
    paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
 
1147
    // strokerect has special rules for CSS when the rect is degenerate:
 
1148
    // if width==0 && height==0, do nothing
 
1149
    // if width==0 || height==0, then just draw line for the other dimension
 
1150
    SkRect r(rect);
 
1151
    bool validW = r.width() > 0;
 
1152
    bool validH = r.height() > 0;
 
1153
    if (validW && validH) {
 
1154
        platformContext()->drawRect(r, paint);
 
1155
    } else if (validW || validH) {
 
1156
        // we are expected to respect the lineJoin, so we can't just call
 
1157
        // drawLine -- we have to create a path that doubles back on itself.
 
1158
        SkPath path;
 
1159
        path.moveTo(r.fLeft, r.fTop);
 
1160
        path.lineTo(r.fRight, r.fBottom);
 
1161
        path.close();
 
1162
        platformContext()->drawPath(path, paint);
 
1163
    }
 
1164
}
 
1165
 
 
1166
void GraphicsContext::rotate(float angleInRadians)
 
1167
{
 
1168
    if (paintingDisabled())
 
1169
        return;
 
1170
 
 
1171
    platformContext()->rotate(WebCoreFloatToSkScalar(angleInRadians * (180.0f / 3.14159265f)));
 
1172
}
 
1173
 
 
1174
void GraphicsContext::translate(float w, float h)
 
1175
{
 
1176
    if (paintingDisabled())
 
1177
        return;
 
1178
 
 
1179
    platformContext()->translate(WebCoreFloatToSkScalar(w), WebCoreFloatToSkScalar(h));
 
1180
}
 
1181
 
 
1182
bool GraphicsContext::isAcceleratedContext() const
 
1183
{
 
1184
    return platformContext()->isAccelerated();
 
1185
}
 
1186
 
 
1187
#if PLATFORM(CHROMIUM) && OS(DARWIN)
 
1188
CGColorSpaceRef deviceRGBColorSpaceRef()
 
1189
{
 
1190
    static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
 
1191
    return deviceSpace;
 
1192
}
 
1193
#endif
 
1194
 
 
1195
void GraphicsContext::platformFillEllipse(const FloatRect& ellipse)
 
1196
{
 
1197
    if (paintingDisabled())
 
1198
        return;
 
1199
 
 
1200
    SkRect rect = ellipse;
 
1201
    SkPaint paint;
 
1202
    platformContext()->setupPaintForFilling(&paint);
 
1203
    platformContext()->drawOval(rect, paint);
 
1204
}
 
1205
 
 
1206
void GraphicsContext::platformStrokeEllipse(const FloatRect& ellipse)
 
1207
{
 
1208
    if (paintingDisabled())
 
1209
        return;
 
1210
 
 
1211
    SkRect rect(ellipse);
 
1212
    SkPaint paint;
 
1213
    platformContext()->setupPaintForStroking(&paint, 0, 0);
 
1214
    platformContext()->drawOval(rect, paint);
 
1215
}
 
1216
 
 
1217
}  // namespace WebCore