summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp
diff options
context:
space:
mode:
authorNicolas Roard <nicolasroard@google.com>2012-04-02 16:16:59 -0700
committerNicolas Roard <nicolasroard@google.com>2012-04-06 11:05:38 -0700
commit64e4b265f84573b97d408f7d3e5aa99a647be057 (patch)
treee349e52565c0cc487526fd68b608f8648678c1c7 /Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp
parentd01f8866730e5ebe8609f82f95cf281432460607 (diff)
downloadexternal_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.cpp648
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();
+}