diff options
author | Nicolas Roard <nicolasroard@google.com> | 2012-04-02 16:16:59 -0700 |
---|---|---|
committer | Nicolas Roard <nicolasroard@google.com> | 2012-04-06 11:05:38 -0700 |
commit | 64e4b265f84573b97d408f7d3e5aa99a647be057 (patch) | |
tree | e349e52565c0cc487526fd68b608f8648678c1c7 /Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp | |
parent | d01f8866730e5ebe8609f82f95cf281432460607 (diff) | |
download | external_webkit-64e4b265f84573b97d408f7d3e5aa99a647be057.zip external_webkit-64e4b265f84573b97d408f7d3e5aa99a647be057.tar.gz external_webkit-64e4b265f84573b97d408f7d3e5aa99a647be057.tar.bz2 |
Implements a recording GraphicsContext
Change-Id: I41feadb23dce25af321331c459eb159c6141831b
Diffstat (limited to 'Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp new file mode 100644 index 0000000..12b53a3 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp @@ -0,0 +1,648 @@ +/* + * Copyright 2006, The Android Open Source Project + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "AffineTransform.h" +#include "Font.h" +#include "Gradient.h" +#include "NotImplemented.h" +#include "Path.h" +#include "Pattern.h" +#include "PlatformGraphicsContext.h" +#include "PlatformGraphicsContextSkia.h" +#include "SkBitmapRef.h" +#include "SkBlurDrawLooper.h" +#include "SkBlurMaskFilter.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkCornerPathEffect.h" +#include "SkDashPathEffect.h" +#include "SkDevice.h" +#include "SkGradientShader.h" +#include "SkPaint.h" +#include "SkString.h" +#include "SkiaUtils.h" +#include "TransformationMatrix.h" +#include "android_graphics.h" + +using namespace std; + +namespace WebCore { + +// This class just holds onto a PlatformContextSkia for GraphicsContext. +class GraphicsContextPlatformPrivate { + WTF_MAKE_NONCOPYABLE(GraphicsContextPlatformPrivate); +public: + GraphicsContextPlatformPrivate(PlatformGraphicsContext* platformContext) + : m_context(platformContext) { } + + PlatformGraphicsContext* context() { return m_context; } + +private: + // Non-owning pointer to the PlatformContext. + PlatformGraphicsContext* m_context; +}; + +static SkShader* extractShader(Pattern* pat, Gradient* grad) +{ + if (pat) + return pat->platformPattern(AffineTransform()); + else if (grad) + return grad->platformGradient(); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height) +{ + PlatformGraphicsContextSkia* pgc = new PlatformGraphicsContextSkia(new SkCanvas, true); + + SkBitmap bitmap; + + bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + bitmap.allocPixels(); + bitmap.eraseColor(0); + pgc->getCanvas()->setBitmapDevice(bitmap); + + GraphicsContext* ctx = new GraphicsContext(pgc); + return ctx; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +void GraphicsContext::platformInit(PlatformGraphicsContext* gc) +{ + if (gc) + gc->setGraphicsContext(this); + m_data = new GraphicsContextPlatformPrivate(gc); + setPaintingDisabled(!gc || gc->isPaintingDisabled()); +} + +void GraphicsContext::platformDestroy() +{ + delete m_data; +} + +void GraphicsContext::savePlatformState() +{ + if (paintingDisabled()) + return; + platformContext()->save(); +} + +void GraphicsContext::restorePlatformState() +{ + if (paintingDisabled()) + return; + platformContext()->restore(); +} + +bool GraphicsContext::willFill() const +{ + return m_state.fillColor.rgb(); +} + +bool GraphicsContext::willStroke() const +{ + return m_state.strokeColor.rgb(); +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + platformContext()->drawRect(rect); +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + platformContext()->drawLine(point1, point2); +} + +void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool /* printing */) +{ + if (paintingDisabled()) + return; + + platformContext()->drawLineForText(pt, width); +} + +void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, + TextCheckingLineStyle style) +{ + if (paintingDisabled()) + return; + + platformContext()->drawLineForTextChecking(pt, width, style); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + platformContext()->drawEllipse(rect); +} + +void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan) +{ + if (paintingDisabled()) + return; + + platformContext()->strokeArc(r, startAngle, angleSpan); +} + +void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, + bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + platformContext()->drawConvexPolygon(numPoints, points, shouldAntialias); +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, + const IntSize& bottomLeft, const IntSize& bottomRight, + const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + platformContext()->fillRoundedRect(rect, topLeft, topRight, + bottomLeft, bottomRight, color, colorSpace); +} + +void GraphicsContext::fillRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + platformContext()->fillRect(rect); +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + platformContext()->fillRect(rect, color, colorSpace); +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + platformContext()->clip(rect); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + platformContext()->clip(path); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + platformContext()->addInnerRoundedRectClip(rect, thickness); +} + +void GraphicsContext::canvasClip(const Path& path) +{ + if (paintingDisabled()) + return; + + platformContext()->canvasClip(path); +} + +void GraphicsContext::clipOut(const IntRect& r) +{ + if (paintingDisabled()) + return; + + platformContext()->clipOut(r); +} + +#if ENABLE(SVG) +void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) +{ + if (paintingDisabled()) + return; + + platformContext()->clipPath(pathToClip, clipRule); +} +#endif + +void GraphicsContext::clipOut(const Path& p) +{ + if (paintingDisabled()) + return; + + platformContext()->clipOut(p); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +#if SVG_SUPPORT +KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext() +{ + return new KRenderingDeviceContextQuartz(platformContext()); +} +#endif + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + platformContext()->beginTransparencyLayer(opacity); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + + platformContext()->endTransparencyLayer(); +} + +/////////////////////////////////////////////////////////////////////////// + +void GraphicsContext::setupFillPaint(SkPaint* paint) +{ + if (paintingDisabled()) + return; + platformContext()->setupPaintFill(paint); +} + +void GraphicsContext::setupStrokePaint(SkPaint* paint) +{ + if (paintingDisabled()) + return; + platformContext()->setupPaintStroke(paint, 0); +} + +bool GraphicsContext::setupShadowPaint(SkPaint* paint, SkPoint* offset) +{ + if (paintingDisabled()) + return false; + return platformContext()->setupPaintShadow(paint, offset); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& c, ColorSpace) +{ + if (paintingDisabled()) + return; + platformContext()->setStrokeColor(c); +} + +void GraphicsContext::setPlatformStrokeThickness(float f) +{ + if (paintingDisabled()) + return; + platformContext()->setStrokeThickness(f); +} + +void GraphicsContext::setPlatformStrokeStyle(StrokeStyle style) +{ + if (paintingDisabled()) + return; + platformContext()->setStrokeStyle(style); +} + +void GraphicsContext::setPlatformFillColor(const Color& c, ColorSpace) +{ + if (paintingDisabled()) + return; + platformContext()->setFillColor(c); +} + +void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace) +{ + if (paintingDisabled()) + return; + + if (blur <= 0) + this->clearPlatformShadow(); + + SkColor c; + if (color.isValid()) + c = color.rgb(); + else + c = SkColorSetARGB(0xFF / 3, 0, 0, 0); // "std" Apple shadow color + platformContext()->setShadow(blur, size.width(), size.height(), c); +} + +void GraphicsContext::clearPlatformShadow() +{ + if (paintingDisabled()) + return; + + platformContext()->setShadow(0, 0, 0, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) +{ + if (paintingDisabled()) + return; + + platformContext()->drawFocusRing(rects, width, offset, color); +} + +void GraphicsContext::drawFocusRing(const Path&, int, int, const Color&) +{ + // Do nothing, since we draw the focus ring independently. +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + ASSERT(!paintingDisabled()); + return m_data->context(); +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + platformContext()->setMiterLimit(limit); +} + +void GraphicsContext::setAlpha(float alpha) +{ + if (paintingDisabled()) + return; + platformContext()->setAlpha(alpha); +} + +void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + platformContext()->setCompositeOperation(op); +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + platformContext()->clearRect(rect); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) +{ + if (paintingDisabled()) + return; + + platformContext()->strokeRect(rect, lineWidth); +} + +void GraphicsContext::setLineCap(LineCap cap) +{ + if (paintingDisabled()) + return; + platformContext()->setLineCap(cap); +} + +#if ENABLE(SVG) +void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) +{ + if (paintingDisabled()) + return; + + platformContext()->setLineDash(dashes, dashOffset); +} +#endif + +void GraphicsContext::setLineJoin(LineJoin join) +{ + if (paintingDisabled()) + return; + platformContext()->setLineJoin(join); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + if (paintingDisabled()) + return; + platformContext()->scale(size); +} + +void GraphicsContext::rotate(float angleInRadians) +{ + if (paintingDisabled()) + return; + platformContext()->rotate(angleInRadians); +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + platformContext()->translate(x, y); +} + +void GraphicsContext::concatCTM(const AffineTransform& affine) +{ + if (paintingDisabled()) + return; + platformContext()->concatCTM(affine); +} + +// This is intended to round the rect to device pixels (through the CTM) +// and then invert the result back into source space, with the hope that when +// it is drawn (through the matrix), it will land in the "right" place (i.e. +// on pixel boundaries). + +// For android, we record this geometry once and then draw it though various +// scale factors as the user zooms, without re-recording. Thus this routine +// should just leave the original geometry alone. + +// If we instead draw into bitmap tiles, we should then perform this +// transform -> round -> inverse step. + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode) +{ + return rect; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ +// Appears to be PDF specific, so we ignore it +} + +void GraphicsContext::setPlatformShouldAntialias(bool useAA) +{ + if (paintingDisabled()) + return; + platformContext()->setShouldAntialias(useAA); +} + +void GraphicsContext::setPlatformFillGradient(Gradient* fillGradient) +{ + if (paintingDisabled()) + return; + SkShader* shader = extractShader(0, fillGradient); + platformContext()->setFillShader(shader); +} + +void GraphicsContext::setPlatformFillPattern(Pattern* fillPattern) +{ + if (paintingDisabled()) + return; + SkShader* shader = extractShader(fillPattern, 0); + platformContext()->setFillShader(shader); +} + +void GraphicsContext::setPlatformStrokeGradient(Gradient* strokeGradient) +{ + if (paintingDisabled()) + return; + SkShader* shader = extractShader(0, strokeGradient); + platformContext()->setStrokeShader(shader); +} + +void GraphicsContext::setPlatformStrokePattern(Pattern* strokePattern) +{ + if (paintingDisabled()) + return; + SkShader* shader = extractShader(strokePattern, 0); + platformContext()->setStrokeShader(shader); +} + +AffineTransform GraphicsContext::getCTM() const +{ + if (paintingDisabled()) + return AffineTransform(); + const SkMatrix& m = platformContext()->getTotalMatrix(); + return AffineTransform(SkScalarToDouble(m.getScaleX()), // a + SkScalarToDouble(m.getSkewY()), // b + SkScalarToDouble(m.getSkewX()), // c + SkScalarToDouble(m.getScaleY()), // d + SkScalarToDouble(m.getTranslateX()), // e + SkScalarToDouble(m.getTranslateY())); // f +} + +void GraphicsContext::setCTM(const AffineTransform& transform) +{ + // The SkPicture mode of Skia does not support SkCanvas::setMatrix(), so we + // can not simply use that method here. We could calculate the transform + // required to achieve the desired matrix and use SkCanvas::concat(), but + // there's currently no need for this. + ASSERT_NOT_REACHED(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void GraphicsContext::fillPath(const Path& pathToFill) +{ + if (paintingDisabled()) + return; + + platformContext()->fillPath(pathToFill, fillRule()); +} + +void GraphicsContext::strokePath(const Path& pathToStroke) +{ + if (paintingDisabled()) + return; + + platformContext()->strokePath(pathToStroke); +} + +InterpolationQuality GraphicsContext::imageInterpolationQuality() const +{ + notImplemented(); + return InterpolationDefault; +} + +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode) +{ +#if 0 + enum InterpolationQuality { + InterpolationDefault, + InterpolationNone, + InterpolationLow, + InterpolationMedium, + InterpolationHigh + }; +#endif + // TODO: record this, so we can know when to use bitmap-filtering when we draw + // ... not sure how meaningful this will be given our playback model. + + // Certainly safe to do nothing for the present. +} + +void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint*, + bool antialias) +{ + if (paintingDisabled()) + return; + + if (numPoints <= 1) + return; + + // FIXME: IMPLEMENT! +} + +void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, + const FloatPoint& point, int h, + const Color& backgroundColor, + ColorSpace colorSpace, int from, + int to, bool isActive) +{ + if (paintingDisabled()) + return; + + platformContext()->drawHighlightForText(font, run, point, h, backgroundColor, + colorSpace, from, to, isActive); +} + +} // namespace WebCore + +/////////////////////////////////////////////////////////////////////////////// + +SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc) +{ + return gc->platformContext()->getCanvas(); +} |