2 * Copyright (c) 2008, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "GraphicsContext.h"
34 #include "NativeImageSkia.h"
35 #include "PlatformContextSkia.h"
36 #include "SkiaUtils.h"
38 #include "skia/ext/image_operations.h"
39 #include "skia/ext/platform_canvas.h"
42 #include "SkColorPriv.h"
44 #include "SkDashPathEffect.h"
46 #include <wtf/MathExtras.h>
48 #if defined(__linux__)
52 // State -----------------------------------------------------------------------
54 // Encapsulates the additional painting state information we store for each
55 // pushed graphics state.
56 struct PlatformContextSkia::State {
61 // Common shader state.
63 SkPorterDuff::Mode m_porterDuffMode;
66 bool m_useAntialiasing;
67 SkDrawLooper* m_looper;
73 WebCore::StrokeStyle m_strokeStyle;
74 SkColor m_strokeColor;
75 float m_strokeThickness;
76 int m_dashRatio; // Ratio of the length of a dash to its width.
78 SkPaint::Cap m_lineCap;
79 SkPaint::Join m_lineJoin;
80 SkDashPathEffect* m_dash;
82 // Text. (See cTextFill & friends in GraphicsContext.h.)
83 int m_textDrawingMode;
85 // Helper function for applying the state's alpha value to the given input
86 // color to produce a new output color.
87 SkColor applyAlpha(SkColor) const;
91 void operator=(const State&);
94 // Note: Keep theses default values in sync with GraphicsContextState.
95 PlatformContextSkia::State::State()
97 , m_porterDuffMode(SkPorterDuff::kSrcOver_Mode)
100 , m_useAntialiasing(true)
102 , m_fillColor(0xFF000000)
103 , m_strokeStyle(WebCore::SolidStroke)
104 , m_strokeColor(WebCore::Color::black)
105 , m_strokeThickness(0)
108 , m_lineCap(SkPaint::kDefault_Cap)
109 , m_lineJoin(SkPaint::kDefault_Join)
111 , m_textDrawingMode(WebCore::cTextFill)
115 PlatformContextSkia::State::State(const State& other)
117 memcpy(this, &other, sizeof(State));
121 m_gradient->safeRef();
122 m_pattern->safeRef();
125 PlatformContextSkia::State::~State()
127 m_looper->safeUnref();
129 m_gradient->safeUnref();
130 m_pattern->safeUnref();
133 SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
135 int s = roundf(m_alpha * 256);
141 int a = SkAlphaMul(SkColorGetA(c), s);
142 return (c & 0x00FFFFFF) | (a << 24);
145 // PlatformContextSkia ---------------------------------------------------------
147 // Danger: canvas can be NULL.
148 PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
150 , m_stateStack(sizeof(State))
152 m_stateStack.append(State());
153 m_state = &m_stateStack.last();
154 #if defined(OS_LINUX)
155 m_gdkskia = m_canvas ? gdk_skia_new(m_canvas) : 0;
159 PlatformContextSkia::~PlatformContextSkia()
161 #if defined(OS_LINUX)
163 g_object_unref(m_gdkskia);
169 void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
174 void PlatformContextSkia::save()
176 m_stateStack.append(*m_state);
177 m_state = &m_stateStack.last();
179 // Save our native canvas.
183 void PlatformContextSkia::restore()
185 m_stateStack.removeLast();
186 m_state = &m_stateStack.last();
188 // Restore our native canvas.
192 void PlatformContextSkia::drawRect(SkRect rect)
195 int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
196 if (fillcolorNotTransparent) {
197 setupPaintForFilling(&paint);
198 canvas()->drawRect(rect, paint);
201 if (m_state->m_strokeStyle != WebCore::NoStroke &&
202 (m_state->m_strokeColor & 0xFF000000)) {
203 if (fillcolorNotTransparent) {
204 // This call is expensive so don't call it unnecessarily.
207 setupPaintForStroking(&paint, &rect, 0);
208 canvas()->drawRect(rect, paint);
212 void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
216 SkPaint defaultPaint;
217 SkASSERT(*paint == defaultPaint);
221 paint->setAntiAlias(m_state->m_useAntialiasing);
222 paint->setPorterDuffXfermode(m_state->m_porterDuffMode);
223 paint->setLooper(m_state->m_looper);
225 if (m_state->m_gradient)
226 paint->setShader(m_state->m_gradient);
227 else if (m_state->m_pattern)
228 paint->setShader(m_state->m_pattern);
231 void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
233 setupPaintCommon(paint);
234 paint->setColor(m_state->applyAlpha(m_state->m_fillColor));
237 float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
239 setupPaintCommon(paint);
240 float width = m_state->m_strokeThickness;
242 // This allows dashing and dotting to work properly for hairline strokes.
246 paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
247 paint->setStyle(SkPaint::kStroke_Style);
248 paint->setStrokeWidth(SkFloatToScalar(width));
249 paint->setStrokeCap(m_state->m_lineCap);
250 paint->setStrokeJoin(m_state->m_lineJoin);
251 paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
253 if (rect != 0 && (static_cast<int>(roundf(width)) & 1))
254 rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
257 paint->setPathEffect(m_state->m_dash);
259 switch (m_state->m_strokeStyle) {
260 case WebCore::NoStroke:
261 case WebCore::SolidStroke:
263 case WebCore::DashedStroke:
264 width = m_state->m_dashRatio * width;
266 case WebCore::DottedStroke:
269 // Determine about how many dashes or dots we should have.
270 int numDashes = length / roundf(width);
271 if (!(numDashes & 1))
272 numDashes++; // Make it odd so we end on a dash/dot.
273 // Use the number of dashes to determine the length of a
274 // dash/dot, which will be approximately width
275 dashLength = SkScalarDiv(SkIntToScalar(length), SkIntToScalar(numDashes));
277 dashLength = SkFloatToScalar(width);
278 SkScalar intervals[2] = { dashLength, dashLength };
279 paint->setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref();
286 void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
288 SkRefCnt_SafeAssign(m_state->m_looper, dl);
291 void PlatformContextSkia::setMiterLimit(float ml)
293 m_state->m_miterLimit = ml;
296 void PlatformContextSkia::setAlpha(float alpha)
298 m_state->m_alpha = alpha;
301 void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
303 m_state->m_lineCap = lc;
306 void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
308 m_state->m_lineJoin = lj;
311 void PlatformContextSkia::setPorterDuffMode(SkPorterDuff::Mode pdm)
313 m_state->m_porterDuffMode = pdm;
316 void PlatformContextSkia::setFillColor(SkColor color)
318 m_state->m_fillColor = color;
321 SkDrawLooper* PlatformContextSkia::getDrawLooper() const
323 return m_state->m_looper;
326 WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const
328 return m_state->m_strokeStyle;
331 void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle)
333 m_state->m_strokeStyle = strokeStyle;
336 void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
338 m_state->m_strokeColor = strokeColor;
341 float PlatformContextSkia::getStrokeThickness() const
343 return m_state->m_strokeThickness;
346 void PlatformContextSkia::setStrokeThickness(float thickness)
348 m_state->m_strokeThickness = thickness;
351 int PlatformContextSkia::getTextDrawingMode() const
353 return m_state->m_textDrawingMode;
356 void PlatformContextSkia::setTextDrawingMode(int mode)
358 // cTextClip is never used, so we assert that it isn't set:
359 // https://bugs.webkit.org/show_bug.cgi?id=21898
360 ASSERT((mode & WebCore::cTextClip) == 0);
361 m_state->m_textDrawingMode = mode;
364 void PlatformContextSkia::setUseAntialiasing(bool enable)
366 m_state->m_useAntialiasing = enable;
369 SkColor PlatformContextSkia::fillColor() const
371 return m_state->m_fillColor;
374 void PlatformContextSkia::beginPath()
379 void PlatformContextSkia::addPath(const SkPath& path)
381 m_path.addPath(path);
384 void PlatformContextSkia::setFillRule(SkPath::FillType fr)
386 m_path.setFillType(fr);
389 void PlatformContextSkia::setGradient(SkShader* gradient)
391 if (gradient != m_state->m_gradient) {
392 m_state->m_gradient->safeUnref();
393 m_state->m_gradient = gradient;
397 void PlatformContextSkia::setPattern(SkShader* pattern)
399 if (pattern != m_state->m_pattern) {
400 m_state->m_pattern->safeUnref();
401 m_state->m_pattern = pattern;
405 void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
407 if (dash != m_state->m_dash) {
408 m_state->m_dash->safeUnref();
409 m_state->m_dash = dash;
413 void PlatformContextSkia::paintSkPaint(const SkRect& rect,
414 const SkPaint& paint)
416 m_canvas->drawRect(rect, paint);
419 const SkBitmap* PlatformContextSkia::bitmap() const
421 return &m_canvas->getDevice()->accessBitmap(false);
424 bool PlatformContextSkia::isPrinting()
426 return m_canvas->getTopPlatformDevice().IsVectorial();