diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
commit | 635860845790a19bf50bbc51ba8fb66a96dde068 (patch) | |
tree | ef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/platform/graphics/skia/PlatformContextSkia.cpp | |
parent | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff) | |
download | external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2 |
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/platform/graphics/skia/PlatformContextSkia.cpp')
-rw-r--r-- | WebCore/platform/graphics/skia/PlatformContextSkia.cpp | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp new file mode 100644 index 0000000..60dbbe0 --- /dev/null +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "GraphicsContext.h" +#include "NativeImageSkia.h" +#include "PlatformContextSkia.h" +#include "SkiaUtils.h" + +#include "skia/ext/image_operations.h" +#include "skia/ext/platform_canvas.h" + +#include "SkBitmap.h" +#include "SkColorPriv.h" +#include "SkShader.h" +#include "SkDashPathEffect.h" + +#include <wtf/MathExtras.h> + +#if defined(__linux__) +#include "GdkSkia.h" +#endif + +// State ----------------------------------------------------------------------- + +// Encapsulates the additional painting state information we store for each +// pushed graphics state. +struct PlatformContextSkia::State { + State(); + State(const State&); + ~State(); + + // Common shader state. + float m_alpha; + SkPorterDuff::Mode m_porterDuffMode; + SkShader* m_gradient; + SkShader* m_pattern; + bool m_useAntialiasing; + SkDrawLooper* m_looper; + + // Fill. + SkColor m_fillColor; + + // Stroke. + WebCore::StrokeStyle m_strokeStyle; + SkColor m_strokeColor; + float m_strokeThickness; + int m_dashRatio; // Ratio of the length of a dash to its width. + float m_miterLimit; + SkPaint::Cap m_lineCap; + SkPaint::Join m_lineJoin; + SkDashPathEffect* m_dash; + + // Text. (See cTextFill & friends in GraphicsContext.h.) + int m_textDrawingMode; + + // Helper function for applying the state's alpha value to the given input + // color to produce a new output color. + SkColor applyAlpha(SkColor) const; + +private: + // Not supported. + void operator=(const State&); +}; + +// Note: Keep theses default values in sync with GraphicsContextState. +PlatformContextSkia::State::State() + : m_alpha(1) + , m_porterDuffMode(SkPorterDuff::kSrcOver_Mode) + , m_gradient(0) + , m_pattern(0) + , m_useAntialiasing(true) + , m_looper(0) + , m_fillColor(0xFF000000) + , m_strokeStyle(WebCore::SolidStroke) + , m_strokeColor(WebCore::Color::black) + , m_strokeThickness(0) + , m_dashRatio(3) + , m_miterLimit(4) + , m_lineCap(SkPaint::kDefault_Cap) + , m_lineJoin(SkPaint::kDefault_Join) + , m_dash(0) + , m_textDrawingMode(WebCore::cTextFill) +{ +} + +PlatformContextSkia::State::State(const State& other) +{ + memcpy(this, &other, sizeof(State)); + + m_looper->safeRef(); + m_dash->safeRef(); + m_gradient->safeRef(); + m_pattern->safeRef(); +} + +PlatformContextSkia::State::~State() +{ + m_looper->safeUnref(); + m_dash->safeUnref(); + m_gradient->safeUnref(); + m_pattern->safeUnref(); +} + +SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const +{ + int s = roundf(m_alpha * 256); + if (s >= 256) + return c; + if (s < 0) + return 0; + + int a = SkAlphaMul(SkColorGetA(c), s); + return (c & 0x00FFFFFF) | (a << 24); +} + +// PlatformContextSkia --------------------------------------------------------- + +// Danger: canvas can be NULL. +PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) + : m_canvas(canvas) + , m_stateStack(sizeof(State)) +{ + m_stateStack.append(State()); + m_state = &m_stateStack.last(); +#if defined(OS_LINUX) + m_gdkskia = m_canvas ? gdk_skia_new(m_canvas) : 0; +#endif +} + +PlatformContextSkia::~PlatformContextSkia() +{ +#if defined(OS_LINUX) + if (m_gdkskia) { + g_object_unref(m_gdkskia); + m_gdkskia = 0; + } +#endif +} + +void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) +{ + m_canvas = canvas; +} + +void PlatformContextSkia::save() +{ + m_stateStack.append(*m_state); + m_state = &m_stateStack.last(); + + // Save our native canvas. + canvas()->save(); +} + +void PlatformContextSkia::restore() +{ + m_stateStack.removeLast(); + m_state = &m_stateStack.last(); + + // Restore our native canvas. + canvas()->restore(); +} + +void PlatformContextSkia::drawRect(SkRect rect) +{ + SkPaint paint; + int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000; + if (fillcolorNotTransparent) { + setupPaintForFilling(&paint); + canvas()->drawRect(rect, paint); + } + + if (m_state->m_strokeStyle != WebCore::NoStroke && + (m_state->m_strokeColor & 0xFF000000)) { + if (fillcolorNotTransparent) { + // This call is expensive so don't call it unnecessarily. + paint.reset(); + } + setupPaintForStroking(&paint, &rect, 0); + canvas()->drawRect(rect, paint); + } +} + +void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const +{ +#ifdef SK_DEBUGx + { + SkPaint defaultPaint; + SkASSERT(*paint == defaultPaint); + } +#endif + + paint->setAntiAlias(m_state->m_useAntialiasing); + paint->setPorterDuffXfermode(m_state->m_porterDuffMode); + paint->setLooper(m_state->m_looper); + + if (m_state->m_gradient) + paint->setShader(m_state->m_gradient); + else if (m_state->m_pattern) + paint->setShader(m_state->m_pattern); +} + +void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const +{ + setupPaintCommon(paint); + paint->setColor(m_state->applyAlpha(m_state->m_fillColor)); +} + +float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const +{ + setupPaintCommon(paint); + float width = m_state->m_strokeThickness; + + // This allows dashing and dotting to work properly for hairline strokes. + if (width == 0) + width = 1; + + paint->setColor(m_state->applyAlpha(m_state->m_strokeColor)); + paint->setStyle(SkPaint::kStroke_Style); + paint->setStrokeWidth(SkFloatToScalar(width)); + paint->setStrokeCap(m_state->m_lineCap); + paint->setStrokeJoin(m_state->m_lineJoin); + paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit)); + + if (rect != 0 && (static_cast<int>(roundf(width)) & 1)) + rect->inset(-SK_ScalarHalf, -SK_ScalarHalf); + + if (m_state->m_dash) + paint->setPathEffect(m_state->m_dash); + else { + switch (m_state->m_strokeStyle) { + case WebCore::NoStroke: + case WebCore::SolidStroke: + break; + case WebCore::DashedStroke: + width = m_state->m_dashRatio * width; + // Fall through. + case WebCore::DottedStroke: + SkScalar dashLength; + if (length) { + // Determine about how many dashes or dots we should have. + int numDashes = length / roundf(width); + if (!(numDashes & 1)) + numDashes++; // Make it odd so we end on a dash/dot. + // Use the number of dashes to determine the length of a + // dash/dot, which will be approximately width + dashLength = SkScalarDiv(SkIntToScalar(length), SkIntToScalar(numDashes)); + } else + dashLength = SkFloatToScalar(width); + SkScalar intervals[2] = { dashLength, dashLength }; + paint->setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref(); + } + } + + return width; +} + +void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl) +{ + SkRefCnt_SafeAssign(m_state->m_looper, dl); +} + +void PlatformContextSkia::setMiterLimit(float ml) +{ + m_state->m_miterLimit = ml; +} + +void PlatformContextSkia::setAlpha(float alpha) +{ + m_state->m_alpha = alpha; +} + +void PlatformContextSkia::setLineCap(SkPaint::Cap lc) +{ + m_state->m_lineCap = lc; +} + +void PlatformContextSkia::setLineJoin(SkPaint::Join lj) +{ + m_state->m_lineJoin = lj; +} + +void PlatformContextSkia::setPorterDuffMode(SkPorterDuff::Mode pdm) +{ + m_state->m_porterDuffMode = pdm; +} + +void PlatformContextSkia::setFillColor(SkColor color) +{ + m_state->m_fillColor = color; +} + +SkDrawLooper* PlatformContextSkia::getDrawLooper() const +{ + return m_state->m_looper; +} + +WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const +{ + return m_state->m_strokeStyle; +} + +void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle) +{ + m_state->m_strokeStyle = strokeStyle; +} + +void PlatformContextSkia::setStrokeColor(SkColor strokeColor) +{ + m_state->m_strokeColor = strokeColor; +} + +float PlatformContextSkia::getStrokeThickness() const +{ + return m_state->m_strokeThickness; +} + +void PlatformContextSkia::setStrokeThickness(float thickness) +{ + m_state->m_strokeThickness = thickness; +} + +int PlatformContextSkia::getTextDrawingMode() const +{ + return m_state->m_textDrawingMode; +} + +void PlatformContextSkia::setTextDrawingMode(int mode) +{ + // cTextClip is never used, so we assert that it isn't set: + // https://bugs.webkit.org/show_bug.cgi?id=21898 + ASSERT((mode & WebCore::cTextClip) == 0); + m_state->m_textDrawingMode = mode; +} + +void PlatformContextSkia::setUseAntialiasing(bool enable) +{ + m_state->m_useAntialiasing = enable; +} + +SkColor PlatformContextSkia::fillColor() const +{ + return m_state->m_fillColor; +} + +void PlatformContextSkia::beginPath() +{ + m_path.reset(); +} + +void PlatformContextSkia::addPath(const SkPath& path) +{ + m_path.addPath(path); +} + +void PlatformContextSkia::setFillRule(SkPath::FillType fr) +{ + m_path.setFillType(fr); +} + +void PlatformContextSkia::setGradient(SkShader* gradient) +{ + if (gradient != m_state->m_gradient) { + m_state->m_gradient->safeUnref(); + m_state->m_gradient = gradient; + } +} + +void PlatformContextSkia::setPattern(SkShader* pattern) +{ + if (pattern != m_state->m_pattern) { + m_state->m_pattern->safeUnref(); + m_state->m_pattern = pattern; + } +} + +void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash) +{ + if (dash != m_state->m_dash) { + m_state->m_dash->safeUnref(); + m_state->m_dash = dash; + } +} + +void PlatformContextSkia::paintSkPaint(const SkRect& rect, + const SkPaint& paint) +{ + m_canvas->drawRect(rect, paint); +} + +const SkBitmap* PlatformContextSkia::bitmap() const +{ + return &m_canvas->getDevice()->accessBitmap(false); +} + +bool PlatformContextSkia::isPrinting() +{ + return m_canvas->getTopPlatformDevice().IsVectorial(); +} |