blob: 6615dd27fcf46c8adfdd43ad04a78b966432586f [file] [log] [blame]
/*
* Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008-2009 Torch Mobile, Inc.
* Copyright (C) 2013 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
*/
#ifndef GraphicsContext_h
#define GraphicsContext_h
#include "platform/PlatformExport.h"
#include "platform/fonts/Font.h"
#include "platform/graphics/DashArray.h"
#include "platform/graphics/DrawLooperBuilder.h"
#include "platform/graphics/GraphicsContextState.h"
#include "platform/graphics/ImageOrientation.h"
#include "platform/graphics/skia/SkiaUtils.h"
#include "third_party/skia/include/core/SkMetaData.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "wtf/Allocator.h"
#include "wtf/Forward.h"
#include "wtf/Noncopyable.h"
#include <memory>
class SkBitmap;
class SkImage;
class SkPaint;
class SkPath;
class SkPicture;
class SkRRect;
class SkTextBlob;
struct SkImageInfo;
struct SkRect;
namespace blink {
class FloatRect;
class FloatRoundedRect;
class ImageBuffer;
class KURL;
class PaintController;
class Path;
class PLATFORM_EXPORT GraphicsContext {
WTF_MAKE_NONCOPYABLE(GraphicsContext);
USING_FAST_MALLOC(GraphicsContext);
public:
enum DisabledMode {
NothingDisabled = 0, // Run as normal.
FullyDisabled = 1 // Do absolutely minimal work to remove the cost of
// the context from performance tests.
};
explicit GraphicsContext(PaintController&,
DisabledMode = NothingDisabled,
SkMetaData* = 0);
~GraphicsContext();
SkCanvas* canvas() { return m_canvas; }
const SkCanvas* canvas() const { return m_canvas; }
PaintController& getPaintController() { return m_paintController; }
bool contextDisabled() const { return m_disabledState; }
// ---------- State management methods -----------------
void save();
void restore();
#if ENABLE(ASSERT)
unsigned saveCount() const;
#endif
float strokeThickness() const {
return immutableState()->getStrokeData().thickness();
}
void setStrokeThickness(float thickness) {
mutableState()->setStrokeThickness(thickness);
}
StrokeStyle getStrokeStyle() const {
return immutableState()->getStrokeData().style();
}
void setStrokeStyle(StrokeStyle style) {
mutableState()->setStrokeStyle(style);
}
Color strokeColor() const { return immutableState()->strokeColor(); }
void setStrokeColor(const Color& color) {
mutableState()->setStrokeColor(color);
}
void setLineCap(LineCap cap) { mutableState()->setLineCap(cap); }
void setLineDash(const DashArray& dashes, float dashOffset) {
mutableState()->setLineDash(dashes, dashOffset);
}
void setLineJoin(LineJoin join) { mutableState()->setLineJoin(join); }
void setMiterLimit(float limit) { mutableState()->setMiterLimit(limit); }
Color fillColor() const { return immutableState()->fillColor(); }
void setFillColor(const Color& color) { mutableState()->setFillColor(color); }
void setShouldAntialias(bool antialias) {
mutableState()->setShouldAntialias(antialias);
}
bool shouldAntialias() const { return immutableState()->shouldAntialias(); }
void setTextDrawingMode(TextDrawingModeFlags mode) {
mutableState()->setTextDrawingMode(mode);
}
TextDrawingModeFlags textDrawingMode() const {
return immutableState()->textDrawingMode();
}
void setImageInterpolationQuality(InterpolationQuality quality) {
mutableState()->setInterpolationQuality(quality);
}
InterpolationQuality imageInterpolationQuality() const {
return immutableState()->getInterpolationQuality();
}
// Specify the device scale factor which may change the way document markers
// and fonts are rendered.
void setDeviceScaleFactor(float factor) { m_deviceScaleFactor = factor; }
float deviceScaleFactor() const { return m_deviceScaleFactor; }
// Returns if the context is a printing context instead of a display
// context. Bitmap shouldn't be resampled when printing to keep the best
// possible quality.
bool printing() const { return m_printing; }
void setPrinting(bool printing) { m_printing = printing; }
SkColorFilter* getColorFilter() const;
void setColorFilter(ColorFilter);
// ---------- End state management methods -----------------
// These draw methods will do both stroking and filling.
// FIXME: ...except drawRect(), which fills properly but always strokes
// using a 1-pixel stroke inset from the rect borders (of the correct
// stroke color).
void drawRect(const IntRect&);
void drawLine(const IntPoint&, const IntPoint&);
void fillPath(const Path&);
void strokePath(const Path&);
void fillEllipse(const FloatRect&);
void strokeEllipse(const FloatRect&);
void fillRect(const FloatRect&);
void fillRect(const FloatRect&,
const Color&,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode);
void fillRoundedRect(const FloatRoundedRect&, const Color&);
void fillDRRect(const FloatRoundedRect&,
const FloatRoundedRect&,
const Color&);
void strokeRect(const FloatRect&, float lineWidth);
void drawPicture(const SkPicture*);
void compositePicture(sk_sp<SkPicture>,
const FloatRect& dest,
const FloatRect& src,
SkXfermode::Mode);
void drawImage(Image*,
const FloatRect& destRect,
const FloatRect* srcRect = nullptr,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode,
RespectImageOrientationEnum = DoNotRespectImageOrientation);
void drawImageRRect(
Image*,
const FloatRoundedRect& dest,
const FloatRect& srcRect,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode,
RespectImageOrientationEnum = DoNotRespectImageOrientation);
void drawTiledImage(Image*,
const FloatRect& destRect,
const FloatPoint& srcPoint,
const FloatSize& tileSize,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode,
const FloatSize& repeatSpacing = FloatSize());
void drawTiledImage(Image*,
const FloatRect& destRect,
const FloatRect& srcRect,
const FloatSize& tileScaleFactor,
Image::TileRule hRule = Image::StretchTile,
Image::TileRule vRule = Image::StretchTile,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode);
// These methods write to the canvas.
// Also drawLine(const IntPoint& point1, const IntPoint& point2) and
// fillRoundedRect().
void drawOval(const SkRect&, const SkPaint&);
void drawPath(const SkPath&, const SkPaint&);
void drawRect(const SkRect&, const SkPaint&);
void drawRRect(const SkRRect&, const SkPaint&);
void clip(const IntRect& rect) { clipRect(rect); }
void clip(const FloatRect& rect) { clipRect(rect); }
void clipRoundedRect(const FloatRoundedRect&,
SkRegion::Op = SkRegion::kIntersect_Op,
AntiAliasingMode = AntiAliased);
void clipOut(const IntRect& rect) {
clipRect(rect, NotAntiAliased, SkRegion::kDifference_Op);
}
void clipOut(const FloatRect& rect) {
clipRect(rect, NotAntiAliased, SkRegion::kDifference_Op);
}
void clipOut(const Path&);
void clipOutRoundedRect(const FloatRoundedRect&);
void clipPath(const SkPath&,
AntiAliasingMode = NotAntiAliased,
SkRegion::Op = SkRegion::kIntersect_Op);
void clipRect(const SkRect&,
AntiAliasingMode = NotAntiAliased,
SkRegion::Op = SkRegion::kIntersect_Op);
void drawText(const Font&, const TextRunPaintInfo&, const FloatPoint&);
void drawText(const Font&,
const TextRunPaintInfo&,
const FloatPoint&,
const SkPaint&);
void drawEmphasisMarks(const Font&,
const TextRunPaintInfo&,
const AtomicString& mark,
const FloatPoint&);
void drawBidiText(
const Font&,
const TextRunPaintInfo&,
const FloatPoint&,
Font::CustomFontNotReadyAction = Font::DoNotPaintIfFontNotReady);
void drawHighlightForText(const Font&,
const TextRun&,
const FloatPoint&,
int h,
const Color& backgroundColor,
int from = 0,
int to = -1);
void drawLineForText(const FloatPoint&, float width, bool printing);
enum DocumentMarkerLineStyle {
DocumentMarkerSpellingLineStyle,
DocumentMarkerGrammarLineStyle
};
void drawLineForDocumentMarker(const FloatPoint&,
float width,
DocumentMarkerLineStyle);
// beginLayer()/endLayer() behave like save()/restore() for CTM and clip
// states. Apply SkXfermode::Mode when the layer is composited on the backdrop
// (i.e. endLayer()).
void beginLayer(float opacity = 1.0f,
SkXfermode::Mode = SkXfermode::kSrcOver_Mode,
const FloatRect* = 0,
ColorFilter = ColorFilterNone,
sk_sp<SkImageFilter> = nullptr);
void endLayer();
// Instead of being dispatched to the active canvas, draw commands following
// beginRecording() are stored in a display list that can be replayed at a
// later time. Pass in the bounding rectangle for the content in the list.
void beginRecording(const FloatRect&);
// Returns a picture with any recorded draw commands since the prerequisite
// call to beginRecording(). The picture is guaranteed to be non-null (but
// not necessarily non-empty), even when the context is disabled.
sk_sp<SkPicture> endRecording();
void setShadow(const FloatSize& offset,
float blur,
const Color&,
DrawLooperBuilder::ShadowTransformMode =
DrawLooperBuilder::ShadowRespectsTransforms,
DrawLooperBuilder::ShadowAlphaMode =
DrawLooperBuilder::ShadowRespectsAlpha,
ShadowMode = DrawShadowAndForeground);
// It is assumed that this draw looper is used only for shadows
// (i.e. a draw looper is set if and only if there is a shadow).
// The builder passed into this method will be destroyed.
void setDrawLooper(std::unique_ptr<DrawLooperBuilder>);
void drawFocusRing(const Vector<IntRect>&,
int width,
int offset,
const Color&);
void drawFocusRing(const Path&, int width, int offset, const Color&);
enum Edge {
NoEdge = 0,
TopEdge = 1 << 1,
RightEdge = 1 << 2,
BottomEdge = 1 << 3,
LeftEdge = 1 << 4
};
typedef unsigned Edges;
void drawInnerShadow(const FloatRoundedRect&,
const Color& shadowColor,
const FloatSize& shadowOffset,
float shadowBlur,
float shadowSpread,
Edges clippedEdges = NoEdge);
const SkPaint& fillPaint() const { return immutableState()->fillPaint(); }
const SkPaint& strokePaint() const { return immutableState()->strokePaint(); }
// ---------- Transformation methods -----------------
void concatCTM(const AffineTransform&);
void scale(float x, float y);
void rotate(float angleInRadians);
void translate(float x, float y);
// ---------- End transformation methods -----------------
SkFilterQuality computeFilterQuality(Image*,
const FloatRect& dest,
const FloatRect& src) const;
// Sets target URL of a clickable area.
void setURLForRect(const KURL&, const IntRect&);
// Sets the destination of a clickable area of a URL fragment (in a URL
// pointing to the same web page). When the area is clicked, the page should
// be scrolled to the location set by setURLDestinationLocation() for the
// destination whose name is |name|.
void setURLFragmentForRect(const String& name, const IntRect&);
// Sets location of a URL destination (a.k.a. anchor) in the page.
void setURLDestinationLocation(const String& name, const IntPoint&);
static void adjustLineToPixelBoundaries(FloatPoint& p1,
FloatPoint& p2,
float strokeWidth,
StrokeStyle);
static int focusRingOutsetExtent(int offset, int width) {
// Unlike normal outlines (whole width is outside of the offset), focus
// rings are drawn with the center of the path aligned with the offset, so
// only half of the width is outside of the offset.
return focusRingOffset(offset) + (focusRingWidth(width) + 1) / 2;
}
#if OS(MACOSX)
static int focusRingWidth(int width) { return width; }
#else
static int focusRingWidth(int width) { return 1; }
#endif
#if DCHECK_IS_ON()
void setInDrawingRecorder(bool);
#endif
static sk_sp<SkColorFilter> WebCoreColorFilterToSkiaColorFilter(ColorFilter);
private:
const GraphicsContextState* immutableState() const { return m_paintState; }
GraphicsContextState* mutableState() {
realizePaintSave();
return m_paintState;
}
template <typename DrawTextFunc>
void drawTextPasses(const DrawTextFunc&);
#if OS(MACOSX)
static inline int focusRingOffset(int offset) { return offset + 2; }
#else
static inline int focusRingOffset(int offset) { return 0; }
static SkPMColor lineColors(int);
static SkPMColor antiColors1(int);
static SkPMColor antiColors2(int);
static void draw1xMarker(SkBitmap*, int);
static void draw2xMarker(SkBitmap*, int);
#endif
void saveLayer(const SkRect* bounds, const SkPaint*);
void restoreLayer();
// Helpers for drawing a focus ring (drawFocusRing)
void drawFocusRingPath(const SkPath&, const Color&, int width);
void drawFocusRingRect(const SkRect&, const Color&, int width);
// SkCanvas wrappers.
void clipRRect(const SkRRect&,
AntiAliasingMode = NotAntiAliased,
SkRegion::Op = SkRegion::kIntersect_Op);
void concat(const SkMatrix&);
// Apply deferred paint state saves
void realizePaintSave() {
if (contextDisabled())
return;
if (m_paintState->saveCount()) {
m_paintState->decrementSaveCount();
++m_paintStateIndex;
if (m_paintStateStack.size() == m_paintStateIndex) {
m_paintStateStack.append(
GraphicsContextState::createAndCopy(*m_paintState));
m_paintState = m_paintStateStack[m_paintStateIndex].get();
} else {
GraphicsContextState* priorPaintState = m_paintState;
m_paintState = m_paintStateStack[m_paintStateIndex].get();
m_paintState->copy(*priorPaintState);
}
}
}
void fillRectWithRoundedHole(const FloatRect&,
const FloatRoundedRect& roundedHoleRect,
const Color&);
const SkMetaData& metaData() const { return m_metaData; }
// null indicates painting is contextDisabled. Never delete this object.
SkCanvas* m_canvas;
PaintController& m_paintController;
// Paint states stack. The state controls the appearance of drawn content, so
// this stack enables local drawing state changes with save()/restore() calls.
// We do not delete from this stack to avoid memory churn.
Vector<std::unique_ptr<GraphicsContextState>> m_paintStateStack;
// Current index on the stack. May not be the last thing on the stack.
unsigned m_paintStateIndex;
// Raw pointer to the current state.
GraphicsContextState* m_paintState;
SkPictureRecorder m_pictureRecorder;
SkMetaData m_metaData;
#if DCHECK_IS_ON()
unsigned m_layerCount;
bool m_disableDestructionChecks;
bool m_inDrawingRecorder;
#endif
const DisabledMode m_disabledState;
float m_deviceScaleFactor;
unsigned m_printing : 1;
unsigned m_hasMetaData : 1;
};
} // namespace blink
#endif // GraphicsContext_h