Replace GrStrokeInfo with GrStyle.
A side effect is that arbitrary path effects can no be pushed deeper into the Ganesh flow for paths. They may be applied by path renderers. GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1957363002 Committed: https://skia.googlesource.com/skia/+/33595bdf4b64a745f6340338d307e806e96c587f Review-Url: https://codereview.chromium.org/1957363002
This commit is contained in:
parent
44d427e048
commit
6663acff01
@ -174,8 +174,6 @@
|
|||||||
'<(skia_src_path)/gpu/GrStencil.h',
|
'<(skia_src_path)/gpu/GrStencil.h',
|
||||||
'<(skia_src_path)/gpu/GrStencilAttachment.cpp',
|
'<(skia_src_path)/gpu/GrStencilAttachment.cpp',
|
||||||
'<(skia_src_path)/gpu/GrStencilAttachment.h',
|
'<(skia_src_path)/gpu/GrStencilAttachment.h',
|
||||||
'<(skia_src_path)/gpu/GrStrokeInfo.cpp',
|
|
||||||
'<(skia_src_path)/gpu/GrStrokeInfo.h',
|
|
||||||
'<(skia_src_path)/gpu/GrStyle.cpp',
|
'<(skia_src_path)/gpu/GrStyle.cpp',
|
||||||
'<(skia_src_path)/gpu/GrStyle.h',
|
'<(skia_src_path)/gpu/GrStyle.h',
|
||||||
'<(skia_src_path)/gpu/GrTessellator.cpp',
|
'<(skia_src_path)/gpu/GrTessellator.cpp',
|
||||||
|
@ -43,7 +43,6 @@ class GrTextBlobCache;
|
|||||||
class GrTextContext;
|
class GrTextContext;
|
||||||
class GrTextureParams;
|
class GrTextureParams;
|
||||||
class GrVertexBuffer;
|
class GrVertexBuffer;
|
||||||
class GrStrokeInfo;
|
|
||||||
class GrSwizzle;
|
class GrSwizzle;
|
||||||
class SkTraceMemoryDump;
|
class SkTraceMemoryDump;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class GrPaint;
|
|||||||
class GrPathProcessor;
|
class GrPathProcessor;
|
||||||
class GrPipelineBuilder;
|
class GrPipelineBuilder;
|
||||||
class GrRenderTarget;
|
class GrRenderTarget;
|
||||||
class GrStrokeInfo;
|
class GrStyle;
|
||||||
class GrSurface;
|
class GrSurface;
|
||||||
class SkDrawFilter;
|
class SkDrawFilter;
|
||||||
struct SkIPoint;
|
struct SkIPoint;
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
|
|
||||||
// TODO: it is odd that we need both the SkPaint in the following 3 methods.
|
// TODO: it is odd that we need both the SkPaint in the following 3 methods.
|
||||||
// We should extract the text parameters from SkPaint and pass them separately
|
// We should extract the text parameters from SkPaint and pass them separately
|
||||||
// akin to GrStrokeInfo (GrTextInfo?)
|
// akin to GrStyle (GrTextInfo?)
|
||||||
virtual void drawText(const GrClip&, const GrPaint&, const SkPaint&,
|
virtual void drawText(const GrClip&, const GrPaint&, const SkPaint&,
|
||||||
const SkMatrix& viewMatrix, const char text[], size_t byteLength,
|
const SkMatrix& viewMatrix, const char text[], size_t byteLength,
|
||||||
SkScalar x, SkScalar y, const SkIRect& clipBounds);
|
SkScalar x, SkScalar y, const SkIRect& clipBounds);
|
||||||
@ -90,19 +90,15 @@ public:
|
|||||||
* Draw the rect using a paint.
|
* Draw the rect using a paint.
|
||||||
* @param paint describes how to color pixels.
|
* @param paint describes how to color pixels.
|
||||||
* @param viewMatrix transformation matrix
|
* @param viewMatrix transformation matrix
|
||||||
* @param strokeInfo the stroke information (width, join, cap), and.
|
* @param style The style to apply. Null means fill. Currently path effects are not
|
||||||
* the dash information (intervals, count, phase).
|
* allowed.
|
||||||
* If strokeInfo == NULL, then the rect is filled.
|
|
||||||
* Otherwise, if stroke width == 0, then the stroke
|
|
||||||
* is always a single pixel thick, else the rect is
|
|
||||||
* mitered/beveled stroked based on stroke width.
|
|
||||||
* The rects coords are used to access the paint (through texture matrix)
|
* The rects coords are used to access the paint (through texture matrix)
|
||||||
*/
|
*/
|
||||||
void drawRect(const GrClip&,
|
void drawRect(const GrClip&,
|
||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRect&,
|
const SkRect&,
|
||||||
const GrStrokeInfo* strokeInfo = nullptr);
|
const GrStyle* style = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a rectangle of shader coordinates to a rectangle and fills that rectangle.
|
* Maps a rectangle of shader coordinates to a rectangle and fills that rectangle.
|
||||||
@ -133,14 +129,13 @@ public:
|
|||||||
* @param paint describes how to color pixels.
|
* @param paint describes how to color pixels.
|
||||||
* @param viewMatrix transformation matrix
|
* @param viewMatrix transformation matrix
|
||||||
* @param rrect the roundrect to draw
|
* @param rrect the roundrect to draw
|
||||||
* @param strokeInfo the stroke information (width, join, cap) and
|
* @param style style to apply to the rrect. Currently path effects are not allowed.
|
||||||
* the dash information (intervals, count, phase).
|
|
||||||
*/
|
*/
|
||||||
void drawRRect(const GrClip&,
|
void drawRRect(const GrClip&,
|
||||||
const GrPaint&,
|
const GrPaint&,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRRect& rrect,
|
const SkRRect& rrect,
|
||||||
const GrStrokeInfo&);
|
const GrStyle& style);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for drawing an SkPath consisting of nested rrects using a paint.
|
* Shortcut for drawing an SkPath consisting of nested rrects using a paint.
|
||||||
@ -164,14 +159,13 @@ public:
|
|||||||
* @param paint describes how to color pixels.
|
* @param paint describes how to color pixels.
|
||||||
* @param viewMatrix transformation matrix
|
* @param viewMatrix transformation matrix
|
||||||
* @param path the path to draw
|
* @param path the path to draw
|
||||||
* @param strokeInfo the stroke information (width, join, cap) and
|
* @param style style to apply to the path.
|
||||||
* the dash information (intervals, count, phase).
|
|
||||||
*/
|
*/
|
||||||
void drawPath(const GrClip&,
|
void drawPath(const GrClip&,
|
||||||
const GrPaint&,
|
const GrPaint&,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath&,
|
const SkPath&,
|
||||||
const GrStrokeInfo&);
|
const GrStyle& style);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws vertices with a paint.
|
* Draws vertices with a paint.
|
||||||
@ -226,14 +220,13 @@ public:
|
|||||||
* @param paint describes how to color pixels.
|
* @param paint describes how to color pixels.
|
||||||
* @param viewMatrix transformation matrix
|
* @param viewMatrix transformation matrix
|
||||||
* @param oval the bounding rect of the oval.
|
* @param oval the bounding rect of the oval.
|
||||||
* @param strokeInfo the stroke information (width, join, cap) and
|
* @param style style to apply to the oval. Currently path effects are not allowed.
|
||||||
* the dash information (intervals, count, phase).
|
|
||||||
*/
|
*/
|
||||||
void drawOval(const GrClip&,
|
void drawOval(const GrClip&,
|
||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRect& oval,
|
const SkRect& oval,
|
||||||
const GrStrokeInfo& strokeInfo);
|
const GrStyle& style);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the image stretched differentially to fit into dst.
|
* Draw the image stretched differentially to fit into dst.
|
||||||
@ -318,7 +311,7 @@ private:
|
|||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& strokeInfo);
|
const GrStyle& style);
|
||||||
|
|
||||||
// This entry point allows the GrTextContext-derived classes to add their batches to
|
// This entry point allows the GrTextContext-derived classes to add their batches to
|
||||||
// the drawTarget.
|
// the drawTarget.
|
||||||
|
@ -13,10 +13,12 @@
|
|||||||
#ifdef GR_TEST_UTILS
|
#ifdef GR_TEST_UTILS
|
||||||
|
|
||||||
#include "GrColor.h"
|
#include "GrColor.h"
|
||||||
|
#include "SkPathEffect.h"
|
||||||
#include "SkRandom.h"
|
#include "SkRandom.h"
|
||||||
#include "SkStrokeRec.h"
|
#include "SkStrokeRec.h"
|
||||||
|
#include "../private/SkTemplates.h"
|
||||||
|
|
||||||
class GrStrokeInfo;
|
class GrStyle;
|
||||||
class SkMatrix;
|
class SkMatrix;
|
||||||
class SkPath;
|
class SkPath;
|
||||||
class SkRRect;
|
class SkRRect;
|
||||||
@ -24,7 +26,7 @@ struct SkRect;
|
|||||||
|
|
||||||
namespace GrTest {
|
namespace GrTest {
|
||||||
/**
|
/**
|
||||||
* A helper for use in Test functions.
|
* Helpers for use in Test functions.
|
||||||
*/
|
*/
|
||||||
const SkMatrix& TestMatrix(SkRandom*);
|
const SkMatrix& TestMatrix(SkRandom*);
|
||||||
const SkMatrix& TestMatrixPreservesRightAngles(SkRandom*);
|
const SkMatrix& TestMatrixPreservesRightAngles(SkRandom*);
|
||||||
@ -36,10 +38,35 @@ const SkRRect& TestRRectSimple(SkRandom*);
|
|||||||
const SkPath& TestPath(SkRandom*);
|
const SkPath& TestPath(SkRandom*);
|
||||||
const SkPath& TestPathConvex(SkRandom*);
|
const SkPath& TestPathConvex(SkRandom*);
|
||||||
SkStrokeRec TestStrokeRec(SkRandom*);
|
SkStrokeRec TestStrokeRec(SkRandom*);
|
||||||
GrStrokeInfo TestStrokeInfo(SkRandom*);
|
/** Creates styles with dash path effects and null path effects */
|
||||||
|
void TestStyle(SkRandom*, GrStyle*);
|
||||||
|
|
||||||
|
// We have a simplified dash path effect here to avoid relying on SkDashPathEffect which
|
||||||
|
// is in the optional build target effects.
|
||||||
|
class TestDashPathEffect : public SkPathEffect {
|
||||||
|
public:
|
||||||
|
static sk_sp<SkPathEffect> Make(const SkScalar* intervals, int count, SkScalar phase) {
|
||||||
|
return sk_sp<SkPathEffect>(new TestDashPathEffect(intervals, count, phase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool filterPath(SkPath* dst, const SkPath&, SkStrokeRec* , const SkRect*) const override;
|
||||||
|
DashType asADash(DashInfo* info) const override;
|
||||||
|
Factory getFactory() const override { return nullptr; }
|
||||||
|
void toString(SkString*) const override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase);
|
||||||
|
|
||||||
|
int fCount;
|
||||||
|
SkAutoTArray<SkScalar> fIntervals;
|
||||||
|
SkScalar fPhase;
|
||||||
|
SkScalar fInitialDashLength;
|
||||||
|
int fInitialDashIndex;
|
||||||
|
SkScalar fIntervalLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GrTest
|
||||||
|
|
||||||
static inline GrColor GrRandomColor(SkRandom* random) {
|
static inline GrColor GrRandomColor(SkRandom* random) {
|
||||||
// There are only a few cases of random colors which interest us
|
// There are only a few cases of random colors which interest us
|
||||||
enum ColorMode {
|
enum ColorMode {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "GrCaps.h"
|
#include "GrCaps.h"
|
||||||
#include "GrContext.h"
|
#include "GrContext.h"
|
||||||
#include "effects/GrSimpleTextureEffect.h"
|
#include "effects/GrSimpleTextureEffect.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "GrTexture.h"
|
#include "GrTexture.h"
|
||||||
#include "GrTextureProvider.h"
|
#include "GrTextureProvider.h"
|
||||||
#include "SkDraw.h"
|
#include "SkDraw.h"
|
||||||
@ -54,11 +54,10 @@ static bool sw_draw_with_mask_filter(GrDrawContext* drawContext,
|
|||||||
const SkMaskFilter* filter,
|
const SkMaskFilter* filter,
|
||||||
const SkIRect& clipBounds,
|
const SkIRect& clipBounds,
|
||||||
GrPaint* grp,
|
GrPaint* grp,
|
||||||
SkStrokeRec::InitStyle style) {
|
SkStrokeRec::InitStyle fillOrHairline) {
|
||||||
SkMask srcM, dstM;
|
SkMask srcM, dstM;
|
||||||
|
|
||||||
if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
|
if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
|
||||||
SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
|
SkMask::kComputeBoundsAndRenderImage_CreateMode, fillOrHairline)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SkAutoMaskFreeImage autoSrc(srcM.fImage);
|
SkAutoMaskFreeImage autoSrc(srcM.fImage);
|
||||||
@ -96,7 +95,7 @@ static bool sw_draw_with_mask_filter(GrDrawContext* drawContext,
|
|||||||
static sk_sp<GrTexture> create_mask_GPU(GrContext* context,
|
static sk_sp<GrTexture> create_mask_GPU(GrContext* context,
|
||||||
SkRect* maskRect,
|
SkRect* maskRect,
|
||||||
const SkPath& devPath,
|
const SkPath& devPath,
|
||||||
SkStrokeRec::InitStyle style,
|
SkStrokeRec::InitStyle fillOrHairline,
|
||||||
bool doAA,
|
bool doAA,
|
||||||
int sampleCnt) {
|
int sampleCnt) {
|
||||||
// This mask will ultimately be drawn as a non-AA rect (see draw_mask).
|
// This mask will ultimately be drawn as a non-AA rect (see draw_mask).
|
||||||
@ -139,7 +138,7 @@ static sk_sp<GrTexture> create_mask_GPU(GrContext* context,
|
|||||||
// the origin using tempPaint.
|
// the origin using tempPaint.
|
||||||
SkMatrix translate;
|
SkMatrix translate;
|
||||||
translate.setTranslate(-maskRect->fLeft, -maskRect->fTop);
|
translate.setTranslate(-maskRect->fLeft, -maskRect->fTop);
|
||||||
drawContext->drawPath(clip, tempPaint, translate, devPath, GrStrokeInfo(style));
|
drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline));
|
||||||
return drawContext->asTexture();;
|
return drawContext->asTexture();;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,52 +148,50 @@ static void draw_path_with_mask_filter(GrContext* context,
|
|||||||
GrPaint* paint,
|
GrPaint* paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkMaskFilter* maskFilter,
|
const SkMaskFilter* maskFilter,
|
||||||
const SkPathEffect* pathEffect,
|
const GrStyle& style,
|
||||||
const GrStrokeInfo& strokeInfo,
|
const SkPath* path,
|
||||||
SkPath* pathPtr,
|
|
||||||
bool pathIsMutable) {
|
bool pathIsMutable) {
|
||||||
SkASSERT(maskFilter);
|
SkASSERT(maskFilter);
|
||||||
|
|
||||||
SkIRect clipBounds;
|
SkIRect clipBounds;
|
||||||
clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds);
|
clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds);
|
||||||
SkTLazy<SkPath> tmpPath;
|
SkTLazy<SkPath> tmpPath;
|
||||||
|
SkStrokeRec::InitStyle fillOrHairline;
|
||||||
|
|
||||||
static const SkRect* cullRect = nullptr; // TODO: what is our bounds?
|
// We just fully apply the style here.
|
||||||
|
if (style.applies()) {
|
||||||
SkASSERT(strokeInfo.isDashed() || !pathEffect);
|
if (!style.applyToPath(tmpPath.init(), &fillOrHairline, *path,
|
||||||
SkStrokeRec::InitStyle maskStyle;
|
GrStyle::MatrixToScaleFactor(viewMatrix))) {
|
||||||
if (strokeInfo.isHairlineStyle()) {
|
return;
|
||||||
maskStyle = SkStrokeRec::kHairline_InitStyle;
|
}
|
||||||
|
pathIsMutable = true;
|
||||||
|
path = tmpPath.get();
|
||||||
|
} else if (style.isSimpleHairline()) {
|
||||||
|
fillOrHairline = SkStrokeRec::kHairline_InitStyle;
|
||||||
} else {
|
} else {
|
||||||
SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
|
SkASSERT(style.isSimpleFill());
|
||||||
SkStrokeRec rec = strokeInfo;
|
fillOrHairline = SkStrokeRec::kFill_InitStyle;
|
||||||
if (strokeInfo.isDashed()) {
|
|
||||||
if (pathEffect->filterPath(strokedPath, *pathPtr, &rec, cullRect)) {
|
|
||||||
pathPtr = strokedPath;
|
|
||||||
pathPtr->setIsVolatile(true);
|
|
||||||
pathIsMutable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rec.applyToPath(strokedPath, *pathPtr)) {
|
|
||||||
// Apply the stroke to the path if there is one
|
|
||||||
pathPtr = strokedPath;
|
|
||||||
pathPtr->setIsVolatile(true);
|
|
||||||
pathIsMutable = true;
|
|
||||||
}
|
|
||||||
maskStyle = SkStrokeRec::kFill_InitStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid possibly allocating a new path in transform if we can
|
|
||||||
SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
|
|
||||||
if (!pathIsMutable) {
|
|
||||||
devPathPtr->setIsVolatile(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform the path into device space
|
// transform the path into device space
|
||||||
pathPtr->transform(viewMatrix, devPathPtr);
|
if (!viewMatrix.isIdentity()) {
|
||||||
|
SkPath* result;
|
||||||
|
if (pathIsMutable) {
|
||||||
|
result = const_cast<SkPath*>(path);
|
||||||
|
} else {
|
||||||
|
if (!tmpPath.isValid()) {
|
||||||
|
tmpPath.init();
|
||||||
|
}
|
||||||
|
result = tmpPath.get();
|
||||||
|
}
|
||||||
|
path->transform(viewMatrix, result);
|
||||||
|
path = result;
|
||||||
|
result->setIsVolatile(true);
|
||||||
|
pathIsMutable = true;
|
||||||
|
}
|
||||||
|
|
||||||
SkRect maskRect;
|
SkRect maskRect;
|
||||||
if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(devPathPtr->getBounds()),
|
if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(path->getBounds()),
|
||||||
clipBounds,
|
clipBounds,
|
||||||
viewMatrix,
|
viewMatrix,
|
||||||
&maskRect)) {
|
&maskRect)) {
|
||||||
@ -210,8 +207,8 @@ static void draw_path_with_mask_filter(GrContext* context,
|
|||||||
paint,
|
paint,
|
||||||
clip,
|
clip,
|
||||||
viewMatrix,
|
viewMatrix,
|
||||||
SkStrokeRec(maskStyle),
|
SkStrokeRec(fillOrHairline),
|
||||||
*devPathPtr)) {
|
*path)) {
|
||||||
// the mask filter was able to draw itself directly, so there's nothing
|
// the mask filter was able to draw itself directly, so there's nothing
|
||||||
// left to do.
|
// left to do.
|
||||||
return;
|
return;
|
||||||
@ -219,8 +216,8 @@ static void draw_path_with_mask_filter(GrContext* context,
|
|||||||
|
|
||||||
sk_sp<GrTexture> mask(create_mask_GPU(context,
|
sk_sp<GrTexture> mask(create_mask_GPU(context,
|
||||||
&maskRect,
|
&maskRect,
|
||||||
*devPathPtr,
|
*path,
|
||||||
maskStyle,
|
fillOrHairline,
|
||||||
paint->isAntiAlias(),
|
paint->isAntiAlias(),
|
||||||
drawContext->numColorSamples()));
|
drawContext->numColorSamples()));
|
||||||
if (mask) {
|
if (mask) {
|
||||||
@ -238,96 +235,59 @@ static void draw_path_with_mask_filter(GrContext* context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sw_draw_with_mask_filter(drawContext, context->textureProvider(),
|
sw_draw_with_mask_filter(drawContext, context->textureProvider(),
|
||||||
clip, viewMatrix, *devPathPtr,
|
clip, viewMatrix, *path,
|
||||||
maskFilter, clipBounds, paint, maskStyle);
|
maskFilter, clipBounds, paint, fillOrHairline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
|
||||||
|
GrDrawContext* drawContext,
|
||||||
|
const GrClip& clip,
|
||||||
|
const SkPath& path,
|
||||||
|
GrPaint* paint,
|
||||||
|
const SkMatrix& viewMatrix,
|
||||||
|
const SkMaskFilter* mf,
|
||||||
|
const GrStyle& style,
|
||||||
|
bool pathIsMutable) {
|
||||||
|
draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf,
|
||||||
|
style, &path, pathIsMutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
|
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
|
||||||
GrDrawContext* drawContext,
|
GrDrawContext* drawContext,
|
||||||
const GrClip& clip,
|
const GrClip& clip,
|
||||||
const SkPath& origPath,
|
const SkPath& origPath,
|
||||||
GrPaint* paint,
|
|
||||||
const SkMatrix& viewMatrix,
|
|
||||||
const SkMaskFilter* mf,
|
|
||||||
const SkPathEffect* pathEffect,
|
|
||||||
const GrStrokeInfo& origStrokeInfo,
|
|
||||||
bool pathIsMutable) {
|
|
||||||
SkPath* pathPtr = const_cast<SkPath*>(&origPath);
|
|
||||||
|
|
||||||
SkTLazy<SkPath> tmpPath;
|
|
||||||
GrStrokeInfo strokeInfo(origStrokeInfo);
|
|
||||||
|
|
||||||
if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(tmpPath.init(), *pathPtr,
|
|
||||||
&strokeInfo, nullptr)) {
|
|
||||||
pathPtr = tmpPath.get();
|
|
||||||
pathPtr->setIsVolatile(true);
|
|
||||||
pathIsMutable = true;
|
|
||||||
pathEffect = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf, pathEffect,
|
|
||||||
strokeInfo, pathPtr, pathIsMutable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
|
|
||||||
GrDrawContext* drawContext,
|
|
||||||
const GrClip& clip,
|
|
||||||
const SkPath& origSrcPath,
|
|
||||||
const SkPaint& paint,
|
const SkPaint& paint,
|
||||||
const SkMatrix& origViewMatrix,
|
const SkMatrix& origViewMatrix,
|
||||||
const SkMatrix* prePathMatrix,
|
const SkMatrix* prePathMatrix,
|
||||||
const SkIRect& clipBounds,
|
const SkIRect& clipBounds,
|
||||||
bool pathIsMutable) {
|
bool pathIsMutable) {
|
||||||
SkASSERT(!pathIsMutable || origSrcPath.isVolatile());
|
SkASSERT(!pathIsMutable || origPath.isVolatile());
|
||||||
|
|
||||||
GrStrokeInfo strokeInfo(paint);
|
|
||||||
// comment out the line below to determine if it is the reason that the chrome mac perf bot
|
|
||||||
// has begun crashing
|
|
||||||
// strokeInfo.setResScale(SkDraw::ComputeResScaleForStroking(origViewMatrix));
|
|
||||||
|
|
||||||
|
GrStyle style(paint);
|
||||||
// If we have a prematrix, apply it to the path, optimizing for the case
|
// If we have a prematrix, apply it to the path, optimizing for the case
|
||||||
// where the original path can in fact be modified in place (even though
|
// where the original path can in fact be modified in place (even though
|
||||||
// its parameter type is const).
|
// its parameter type is const).
|
||||||
SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
|
|
||||||
|
const SkPath* path = &origPath;
|
||||||
SkTLazy<SkPath> tmpPath;
|
SkTLazy<SkPath> tmpPath;
|
||||||
SkTLazy<SkPath> effectPath;
|
|
||||||
SkPathEffect* pathEffect = paint.getPathEffect();
|
|
||||||
|
|
||||||
SkMatrix viewMatrix = origViewMatrix;
|
SkMatrix viewMatrix = origViewMatrix;
|
||||||
|
|
||||||
if (prePathMatrix) {
|
if (prePathMatrix) {
|
||||||
// stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix.
|
// Styling, blurs, and shading are supposed to be applied *after* the prePathMatrix.
|
||||||
// The pre-path-matrix also should not affect shading.
|
if (!paint.getMaskFilter() && !paint.getShader() && !style.applies()) {
|
||||||
if (!paint.getMaskFilter() && !pathEffect && !paint.getShader() &&
|
|
||||||
(strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) {
|
|
||||||
viewMatrix.preConcat(*prePathMatrix);
|
viewMatrix.preConcat(*prePathMatrix);
|
||||||
} else {
|
} else {
|
||||||
SkPath* result = pathPtr;
|
SkPath* result = pathIsMutable ? const_cast<SkPath*>(path) : tmpPath.init();
|
||||||
|
|
||||||
if (!pathIsMutable) {
|
|
||||||
result = tmpPath.init();
|
|
||||||
result->setIsVolatile(true);
|
|
||||||
pathIsMutable = true;
|
pathIsMutable = true;
|
||||||
}
|
path->transform(*prePathMatrix, result);
|
||||||
// should I push prePathMatrix on our MV stack temporarily, instead
|
path = result;
|
||||||
// of applying it here? See SkDraw.cpp
|
result->setIsVolatile(true);
|
||||||
pathPtr->transform(*prePathMatrix, result);
|
|
||||||
pathPtr = result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// at this point we're done with prePathMatrix
|
// at this point we're done with prePathMatrix
|
||||||
SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
|
SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
|
||||||
|
|
||||||
SkTLazy<SkPath> tmpPath2;
|
|
||||||
|
|
||||||
if (!strokeInfo.isDashed() && pathEffect &&
|
|
||||||
pathEffect->filterPath(tmpPath2.init(), *pathPtr, &strokeInfo, nullptr)) {
|
|
||||||
pathPtr = tmpPath2.get();
|
|
||||||
pathPtr->setIsVolatile(true);
|
|
||||||
pathIsMutable = true;
|
|
||||||
pathEffect = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
GrPaint grPaint;
|
GrPaint grPaint;
|
||||||
if (!SkPaintToGrPaint(context, paint, viewMatrix, drawContext->isGammaCorrect(),
|
if (!SkPaintToGrPaint(context, paint, viewMatrix, drawContext->isGammaCorrect(),
|
||||||
&grPaint)) {
|
&grPaint)) {
|
||||||
@ -336,9 +296,9 @@ void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
|
|||||||
|
|
||||||
if (paint.getMaskFilter()) {
|
if (paint.getMaskFilter()) {
|
||||||
draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMatrix,
|
draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMatrix,
|
||||||
paint.getMaskFilter(), pathEffect, strokeInfo,
|
paint.getMaskFilter(), style,
|
||||||
pathPtr, pathIsMutable);
|
path, pathIsMutable);
|
||||||
} else {
|
} else {
|
||||||
drawContext->drawPath(clip, grPaint, viewMatrix, *pathPtr, strokeInfo);
|
drawContext->drawPath(clip, grPaint, viewMatrix, *path, style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class GrContext;
|
|||||||
class GrDrawContext;
|
class GrDrawContext;
|
||||||
class GrPaint;
|
class GrPaint;
|
||||||
class GrRenderTarget;
|
class GrRenderTarget;
|
||||||
class GrStrokeInfo;
|
class GrStyle;
|
||||||
struct SkIRect;
|
struct SkIRect;
|
||||||
class SkMaskFilter;
|
class SkMaskFilter;
|
||||||
class SkMatrix;
|
class SkMatrix;
|
||||||
@ -50,8 +50,7 @@ namespace GrBlurUtils {
|
|||||||
GrPaint*,
|
GrPaint*,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkMaskFilter*,
|
const SkMaskFilter*,
|
||||||
const SkPathEffect*,
|
const GrStyle&,
|
||||||
const GrStrokeInfo&,
|
|
||||||
bool pathIsMutable);
|
bool pathIsMutable);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -85,7 +85,6 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
|
|||||||
if (path.isInverseFillType()) {
|
if (path.isInverseFillType()) {
|
||||||
path.toggleInverseFillType();
|
path.toggleInverseFillType();
|
||||||
}
|
}
|
||||||
GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
|
|
||||||
|
|
||||||
GrPathRendererChain::DrawType type;
|
GrPathRendererChain::DrawType type;
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
|
|||||||
canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
|
canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
|
||||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||||
canDrawArgs.fPath = &path;
|
canDrawArgs.fPath = &path;
|
||||||
canDrawArgs.fStroke = &stroke;
|
canDrawArgs.fStyle = &GrStyle::SimpleFill();
|
||||||
canDrawArgs.fAntiAlias = element->isAA();
|
canDrawArgs.fAntiAlias = element->isAA();
|
||||||
canDrawArgs.fIsStencilDisabled = isStencilDisabled;
|
canDrawArgs.fIsStencilDisabled = isStencilDisabled;
|
||||||
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
|
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
|
||||||
@ -591,7 +590,7 @@ static void draw_element(GrDrawContext* dc,
|
|||||||
path.toggleInverseFillType();
|
path.toggleInverseFillType();
|
||||||
}
|
}
|
||||||
|
|
||||||
dc->drawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo());
|
dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -785,7 +784,6 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
|||||||
// stencil with arbitrary stencil settings.
|
// stencil with arbitrary stencil settings.
|
||||||
GrPathRenderer::StencilSupport stencilSupport;
|
GrPathRenderer::StencilSupport stencilSupport;
|
||||||
|
|
||||||
GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
|
|
||||||
SkRegion::Op op = element->getOp();
|
SkRegion::Op op = element->getOp();
|
||||||
|
|
||||||
GrPathRenderer* pr = nullptr;
|
GrPathRenderer* pr = nullptr;
|
||||||
@ -806,7 +804,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
|||||||
canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
|
canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
|
||||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||||
canDrawArgs.fPath = &clipPath;
|
canDrawArgs.fPath = &clipPath;
|
||||||
canDrawArgs.fStroke = &stroke;
|
canDrawArgs.fStyle = &GrStyle::SimpleFill();
|
||||||
canDrawArgs.fAntiAlias = false;
|
canDrawArgs.fAntiAlias = false;
|
||||||
canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled();
|
canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled();
|
||||||
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
|
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
|
||||||
@ -861,7 +859,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
|||||||
args.fColor = GrColor_WHITE;
|
args.fColor = GrColor_WHITE;
|
||||||
args.fViewMatrix = &viewMatrix;
|
args.fViewMatrix = &viewMatrix;
|
||||||
args.fPath = &clipPath;
|
args.fPath = &clipPath;
|
||||||
args.fStroke = &stroke;
|
args.fStyle = &GrStyle::SimpleFill();
|
||||||
args.fAntiAlias = false;
|
args.fAntiAlias = false;
|
||||||
args.fGammaCorrect = false;
|
args.fGammaCorrect = false;
|
||||||
pr->drawPath(args);
|
pr->drawPath(args);
|
||||||
@ -896,7 +894,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
|||||||
args.fColor = GrColor_WHITE;
|
args.fColor = GrColor_WHITE;
|
||||||
args.fViewMatrix = &viewMatrix;
|
args.fViewMatrix = &viewMatrix;
|
||||||
args.fPath = &clipPath;
|
args.fPath = &clipPath;
|
||||||
args.fStroke = &stroke;
|
args.fStyle = &GrStyle::SimpleFill();
|
||||||
args.fAntiAlias = false;
|
args.fAntiAlias = false;
|
||||||
args.fGammaCorrect = false;
|
args.fGammaCorrect = false;
|
||||||
pr->drawPath(args);
|
pr->drawPath(args);
|
||||||
@ -1100,7 +1098,6 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
|
|||||||
|
|
||||||
helper.init(maskSpaceIBounds, &translate, false);
|
helper.init(maskSpaceIBounds, &translate, false);
|
||||||
helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x00);
|
helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x00);
|
||||||
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
|
||||||
|
|
||||||
for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
|
for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
|
||||||
const Element* element = iter.get();
|
const Element* element = iter.get();
|
||||||
@ -1119,7 +1116,8 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
|
|||||||
SkPath clipPath;
|
SkPath clipPath;
|
||||||
element->asPath(&clipPath);
|
element->asPath(&clipPath);
|
||||||
clipPath.toggleInverseFillType();
|
clipPath.toggleInverseFillType();
|
||||||
helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA(), 0x00);
|
helper.draw(clipPath, GrStyle::SimpleFill(), SkRegion::kReplace_Op, element->isAA(),
|
||||||
|
0x00);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,7 +1128,7 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
|
|||||||
} else {
|
} else {
|
||||||
SkPath path;
|
SkPath path;
|
||||||
element->asPath(&path);
|
element->asPath(&path);
|
||||||
helper.draw(path, stroke, op, element->isAA(), 0xFF);
|
helper.draw(path, GrStyle::SimpleFill(), op, element->isAA(), 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,18 +279,22 @@ void GrDrawContext::drawRect(const GrClip& clip,
|
|||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRect& rect,
|
const SkRect& rect,
|
||||||
const GrStrokeInfo* strokeInfo) {
|
const GrStyle* style) {
|
||||||
|
if (!style) {
|
||||||
|
style = &GrStyle::SimpleFill();
|
||||||
|
}
|
||||||
ASSERT_SINGLE_OWNER
|
ASSERT_SINGLE_OWNER
|
||||||
RETURN_IF_ABANDONED
|
RETURN_IF_ABANDONED
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect");
|
GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect");
|
||||||
|
|
||||||
// Dashing should've been devolved to a path in SkGpuDevice
|
// Path effects should've been devolved to a path in SkGpuDevice
|
||||||
SkASSERT(!strokeInfo || !strokeInfo->isDashed());
|
SkASSERT(!style->pathEffect());
|
||||||
|
|
||||||
AutoCheckFlush acf(fDrawingManager);
|
AutoCheckFlush acf(fDrawingManager);
|
||||||
|
|
||||||
SkScalar width = !strokeInfo ? -1 : strokeInfo->getWidth();
|
const SkStrokeRec& stroke = style->strokeRec();
|
||||||
|
SkScalar width = stroke.getWidth();
|
||||||
|
|
||||||
// Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
|
// Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
|
||||||
// cases where the RT is fully inside a stroke.
|
// cases where the RT is fully inside a stroke.
|
||||||
@ -337,7 +341,7 @@ void GrDrawContext::drawRect(const GrClip& clip,
|
|||||||
// The stroke path needs the rect to remain axis aligned (no rotation or skew).
|
// The stroke path needs the rect to remain axis aligned (no rotation or skew).
|
||||||
if (viewMatrix.rectStaysRect()) {
|
if (viewMatrix.rectStaysRect()) {
|
||||||
batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect,
|
batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect,
|
||||||
*strokeInfo));
|
stroke));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Non-AA hairlines are snapped to pixel centers to make which pixels are hit
|
// Non-AA hairlines are snapped to pixel centers to make which pixels are hit
|
||||||
@ -367,8 +371,7 @@ void GrDrawContext::drawRect(const GrClip& clip,
|
|||||||
SkPath path;
|
SkPath path;
|
||||||
path.setIsVolatile(true);
|
path.setIsVolatile(true);
|
||||||
path.addRect(rect);
|
path.addRect(rect);
|
||||||
this->internalDrawPath(clip, paint, viewMatrix, path,
|
this->internalDrawPath(clip, paint, viewMatrix, path, *style);
|
||||||
strokeInfo ? *strokeInfo : GrStrokeInfo::FillInfo());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
|
bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
|
||||||
@ -536,7 +539,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
|
|||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRRect& rrect,
|
const SkRRect& rrect,
|
||||||
const GrStrokeInfo& strokeInfo) {
|
const GrStyle& style) {
|
||||||
ASSERT_SINGLE_OWNER
|
ASSERT_SINGLE_OWNER
|
||||||
RETURN_IF_ABANDONED
|
RETURN_IF_ABANDONED
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
@ -546,8 +549,8 @@ void GrDrawContext::drawRRect(const GrClip& clip,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
|
SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
|
||||||
|
const SkStrokeRec stroke = style.strokeRec();
|
||||||
AutoCheckFlush acf(fDrawingManager);
|
AutoCheckFlush acf(fDrawingManager);
|
||||||
|
|
||||||
if (should_apply_coverage_aa(paint, fRenderTarget.get())) {
|
if (should_apply_coverage_aa(paint, fRenderTarget.get())) {
|
||||||
@ -556,7 +559,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
|
|||||||
SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateRRectBatch(paint.getColor(),
|
SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateRRectBatch(paint.getColor(),
|
||||||
viewMatrix,
|
viewMatrix,
|
||||||
rrect,
|
rrect,
|
||||||
strokeInfo,
|
stroke,
|
||||||
shaderCaps));
|
shaderCaps));
|
||||||
if (batch) {
|
if (batch) {
|
||||||
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
||||||
@ -568,7 +571,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
|
|||||||
SkPath path;
|
SkPath path;
|
||||||
path.setIsVolatile(true);
|
path.setIsVolatile(true);
|
||||||
path.addRRect(rrect);
|
path.addRRect(rrect);
|
||||||
this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
|
this->internalDrawPath(clip, paint, viewMatrix, path, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrDrawContext::drawFilledDRRect(const GrClip& clip,
|
bool GrDrawContext::drawFilledDRRect(const GrClip& clip,
|
||||||
@ -654,7 +657,7 @@ void GrDrawContext::drawDRRect(const GrClip& clip,
|
|||||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||||
|
|
||||||
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
||||||
this->internalDrawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo());
|
this->internalDrawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -663,7 +666,7 @@ void GrDrawContext::drawOval(const GrClip& clip,
|
|||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRect& oval,
|
const SkRect& oval,
|
||||||
const GrStrokeInfo& strokeInfo) {
|
const GrStyle& style) {
|
||||||
ASSERT_SINGLE_OWNER
|
ASSERT_SINGLE_OWNER
|
||||||
RETURN_IF_ABANDONED
|
RETURN_IF_ABANDONED
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
@ -673,16 +676,16 @@ void GrDrawContext::drawOval(const GrClip& clip,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
|
SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
|
||||||
|
|
||||||
AutoCheckFlush acf(fDrawingManager);
|
AutoCheckFlush acf(fDrawingManager);
|
||||||
|
const SkStrokeRec& stroke = style.strokeRec();
|
||||||
if (should_apply_coverage_aa(paint, fRenderTarget.get())) {
|
if (should_apply_coverage_aa(paint, fRenderTarget.get())) {
|
||||||
GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
|
GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
|
||||||
SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
|
SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
|
||||||
viewMatrix,
|
viewMatrix,
|
||||||
oval,
|
oval,
|
||||||
strokeInfo,
|
stroke,
|
||||||
shaderCaps));
|
shaderCaps));
|
||||||
if (batch) {
|
if (batch) {
|
||||||
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
||||||
@ -694,7 +697,7 @@ void GrDrawContext::drawOval(const GrClip& clip,
|
|||||||
SkPath path;
|
SkPath path;
|
||||||
path.setIsVolatile(true);
|
path.setIsVolatile(true);
|
||||||
path.addOval(oval);
|
path.addOval(oval);
|
||||||
this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
|
this->internalDrawPath(clip, paint, viewMatrix, path, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrDrawContext::drawImageNine(const GrClip& clip,
|
void GrDrawContext::drawImageNine(const GrClip& clip,
|
||||||
@ -721,11 +724,7 @@ void GrDrawContext::drawImageNine(const GrClip& clip,
|
|||||||
|
|
||||||
|
|
||||||
// Can 'path' be drawn as a pair of filled nested rectangles?
|
// Can 'path' be drawn as a pair of filled nested rectangles?
|
||||||
static bool is_nested_rects(const SkMatrix& viewMatrix,
|
static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
|
||||||
const SkPath& path,
|
|
||||||
const SkStrokeRec& stroke,
|
|
||||||
SkRect rects[2]) {
|
|
||||||
SkASSERT(stroke.isFillStyle());
|
|
||||||
|
|
||||||
if (path.isInverseFillType()) {
|
if (path.isInverseFillType()) {
|
||||||
return false;
|
return false;
|
||||||
@ -799,7 +798,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
|
|||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& strokeInfo) {
|
const GrStyle& style) {
|
||||||
ASSERT_SINGLE_OWNER
|
ASSERT_SINGLE_OWNER
|
||||||
RETURN_IF_ABANDONED
|
RETURN_IF_ABANDONED
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
@ -814,12 +813,12 @@ void GrDrawContext::drawPath(const GrClip& clip,
|
|||||||
|
|
||||||
AutoCheckFlush acf(fDrawingManager);
|
AutoCheckFlush acf(fDrawingManager);
|
||||||
|
|
||||||
if (should_apply_coverage_aa(paint, fRenderTarget.get()) && !strokeInfo.isDashed()) {
|
if (should_apply_coverage_aa(paint, fRenderTarget.get()) && !style.pathEffect()) {
|
||||||
if (strokeInfo.getWidth() < 0 && !path.isConvex()) {
|
if (style.isSimpleFill() && !path.isConvex()) {
|
||||||
// Concave AA paths are expensive - try to avoid them for special cases
|
// Concave AA paths are expensive - try to avoid them for special cases
|
||||||
SkRect rects[2];
|
SkRect rects[2];
|
||||||
|
|
||||||
if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
|
if (fills_as_nested_rects(viewMatrix, path, rects)) {
|
||||||
SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
|
SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
|
||||||
paint.getColor(), viewMatrix, rects));
|
paint.getColor(), viewMatrix, rects));
|
||||||
if (batch) {
|
if (batch) {
|
||||||
@ -837,7 +836,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
|
|||||||
SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
|
SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
|
||||||
viewMatrix,
|
viewMatrix,
|
||||||
ovalRect,
|
ovalRect,
|
||||||
strokeInfo,
|
style.strokeRec(),
|
||||||
shaderCaps));
|
shaderCaps));
|
||||||
if (batch) {
|
if (batch) {
|
||||||
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
|
||||||
@ -852,7 +851,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
|
|||||||
// cache. This presents a potential hazard for buffered drawing. However,
|
// cache. This presents a potential hazard for buffered drawing. However,
|
||||||
// the writePixels that uploads to the scratch will perform a flush so we're
|
// the writePixels that uploads to the scratch will perform a flush so we're
|
||||||
// OK.
|
// OK.
|
||||||
this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
|
this->internalDrawPath(clip, paint, viewMatrix, path, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
||||||
@ -892,7 +891,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
|||||||
canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps();
|
canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps();
|
||||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||||
canDrawArgs.fPath = &path;
|
canDrawArgs.fPath = &path;
|
||||||
canDrawArgs.fStroke = &GrStrokeInfo::FillInfo();
|
canDrawArgs.fStyle = &GrStyle::SimpleFill();
|
||||||
canDrawArgs.fAntiAlias = useCoverageAA;
|
canDrawArgs.fAntiAlias = useCoverageAA;
|
||||||
canDrawArgs.fIsStencilDisabled = isStencilDisabled;
|
canDrawArgs.fIsStencilDisabled = isStencilDisabled;
|
||||||
canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
|
canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
|
||||||
@ -923,7 +922,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
|||||||
args.fColor = GrColor_WHITE;
|
args.fColor = GrColor_WHITE;
|
||||||
args.fViewMatrix = &viewMatrix;
|
args.fViewMatrix = &viewMatrix;
|
||||||
args.fPath = &path;
|
args.fPath = &path;
|
||||||
args.fStroke = &GrStrokeInfo::FillInfo();
|
args.fStyle = &GrStyle::SimpleFill();
|
||||||
args.fAntiAlias = useCoverageAA;
|
args.fAntiAlias = useCoverageAA;
|
||||||
args.fGammaCorrect = fDrawContext->isGammaCorrect();
|
args.fGammaCorrect = fDrawContext->isGammaCorrect();
|
||||||
pr->drawPath(args);
|
pr->drawPath(args);
|
||||||
@ -933,16 +932,12 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
|||||||
void GrDrawContext::internalDrawPath(const GrClip& clip,
|
void GrDrawContext::internalDrawPath(const GrClip& clip,
|
||||||
const GrPaint& paint,
|
const GrPaint& paint,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath& path,
|
const SkPath& origPath,
|
||||||
const GrStrokeInfo& strokeInfo) {
|
const GrStyle& origStyle) {
|
||||||
ASSERT_SINGLE_OWNER
|
ASSERT_SINGLE_OWNER
|
||||||
RETURN_IF_ABANDONED
|
RETURN_IF_ABANDONED
|
||||||
SkASSERT(!path.isEmpty());
|
SkASSERT(!origPath.isEmpty());
|
||||||
|
|
||||||
// An Assumption here is that path renderer would use some form of tweaking
|
|
||||||
// the src color (either the input alpha or in the frag shader) to implement
|
|
||||||
// aa. If we have some future driver-mojo path AA that can do the right
|
|
||||||
// thing WRT to the blend then we'll need some query on the PR.
|
|
||||||
bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get());
|
bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get());
|
||||||
const bool isStencilDisabled = true;
|
const bool isStencilDisabled = true;
|
||||||
bool isStencilBufferMSAA = fRenderTarget->isStencilBufferMultisampled();
|
bool isStencilBufferMSAA = fRenderTarget->isStencilBufferMultisampled();
|
||||||
@ -951,61 +946,65 @@ void GrDrawContext::internalDrawPath(const GrClip& clip,
|
|||||||
useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
|
useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
|
||||||
: GrPathRendererChain::kColor_DrawType;
|
: GrPathRendererChain::kColor_DrawType;
|
||||||
|
|
||||||
const SkPath* pathPtr = &path;
|
|
||||||
SkTLazy<SkPath> tmpPath;
|
SkTLazy<SkPath> tmpPath;
|
||||||
const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
|
SkTLazy<GrStyle> tmpStyle;
|
||||||
|
|
||||||
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||||
canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
|
canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
|
||||||
canDrawArgs.fViewMatrix = &viewMatrix;
|
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||||
canDrawArgs.fPath = pathPtr;
|
canDrawArgs.fPath = &origPath;
|
||||||
canDrawArgs.fStroke = strokeInfoPtr;
|
canDrawArgs.fStyle = &origStyle;
|
||||||
canDrawArgs.fAntiAlias = useCoverageAA;
|
canDrawArgs.fAntiAlias = useCoverageAA;
|
||||||
canDrawArgs.fIsStencilDisabled = isStencilDisabled;
|
canDrawArgs.fIsStencilDisabled = isStencilDisabled;
|
||||||
canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
|
canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
|
||||||
|
|
||||||
// Try a 1st time without stroking the path and without allowing the SW renderer
|
// Try a 1st time without applying any of the style to the geometry (and barring sw)
|
||||||
GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
|
GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
|
||||||
|
SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
|
||||||
|
|
||||||
GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
|
if (!pr && canDrawArgs.fStyle->pathEffect()) {
|
||||||
if (nullptr == pr && strokeInfo.isDashed()) {
|
// It didn't work above, so try again with the path effect applied.
|
||||||
// It didn't work above, so try again with dashed stroke converted to a dashless stroke.
|
SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
|
||||||
if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
|
if (!canDrawArgs.fStyle->applyPathEffectToPath(tmpPath.init(), &rec, *canDrawArgs.fPath,
|
||||||
|
styleScale)) {
|
||||||
|
GrStyle noPathEffect(canDrawArgs.fStyle->strokeRec(), nullptr);
|
||||||
|
this->internalDrawPath(clip, paint, viewMatrix, *canDrawArgs.fPath, noPathEffect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pathPtr = tmpPath.get();
|
tmpStyle.init(rec, nullptr);
|
||||||
if (pathPtr->isEmpty()) {
|
canDrawArgs.fPath = tmpPath.get();
|
||||||
|
canDrawArgs.fStyle = tmpStyle.get();
|
||||||
|
if (canDrawArgs.fPath->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strokeInfoPtr = &dashlessStrokeInfo;
|
|
||||||
|
|
||||||
canDrawArgs.fPath = pathPtr;
|
|
||||||
canDrawArgs.fStroke = strokeInfoPtr;
|
|
||||||
|
|
||||||
pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
|
pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
|
||||||
}
|
}
|
||||||
|
if (!pr) {
|
||||||
if (nullptr == pr) {
|
SkASSERT(!canDrawArgs.fStyle->pathEffect());
|
||||||
if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
|
if (canDrawArgs.fStyle->strokeRec().needToApply()) {
|
||||||
!strokeInfoPtr->isFillStyle()) {
|
|
||||||
// It didn't work above, so try again with stroke converted to a fill.
|
|
||||||
if (!tmpPath.isValid()) {
|
if (!tmpPath.isValid()) {
|
||||||
tmpPath.init();
|
tmpPath.init();
|
||||||
}
|
}
|
||||||
dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
|
// It didn't work above, so try again by applying the stroke to the geometry.
|
||||||
if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
|
SkStrokeRec::InitStyle fillOrHairline;
|
||||||
|
if (!canDrawArgs.fStyle->applyToPath(tmpPath.get(), &fillOrHairline,
|
||||||
|
*canDrawArgs.fPath, styleScale)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pathPtr = tmpPath.get();
|
if (!tmpStyle.isValid()) {
|
||||||
if (pathPtr->isEmpty()) {
|
tmpStyle.init(fillOrHairline);
|
||||||
return;
|
} else {
|
||||||
|
tmpStyle.get()->resetToInitStyle(fillOrHairline);
|
||||||
}
|
}
|
||||||
dashlessStrokeInfo.setFillStyle();
|
canDrawArgs.fPath = tmpPath.get();
|
||||||
strokeInfoPtr = &dashlessStrokeInfo;
|
canDrawArgs.fStyle = tmpStyle.get();
|
||||||
|
if (canDrawArgs.fPath->isEmpty()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
canDrawArgs.fPath = pathPtr;
|
pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
|
||||||
canDrawArgs.fStroke = strokeInfoPtr;
|
}
|
||||||
|
|
||||||
// This time, allow SW renderer
|
// This time, allow SW renderer
|
||||||
pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
|
pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
|
||||||
@ -1026,8 +1025,8 @@ void GrDrawContext::internalDrawPath(const GrClip& clip,
|
|||||||
args.fPipelineBuilder = &pipelineBuilder;
|
args.fPipelineBuilder = &pipelineBuilder;
|
||||||
args.fColor = paint.getColor();
|
args.fColor = paint.getColor();
|
||||||
args.fViewMatrix = &viewMatrix;
|
args.fViewMatrix = &viewMatrix;
|
||||||
args.fPath = pathPtr;
|
args.fPath = canDrawArgs.fPath;
|
||||||
args.fStroke = strokeInfoPtr;
|
args.fStyle = canDrawArgs.fStyle;
|
||||||
args.fAntiAlias = useCoverageAA;
|
args.fAntiAlias = useCoverageAA;
|
||||||
args.fGammaCorrect = this->isGammaCorrect();
|
args.fGammaCorrect = this->isGammaCorrect();
|
||||||
pr->drawPath(args);
|
pr->drawPath(args);
|
||||||
|
@ -6,13 +6,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "GrPath.h"
|
#include "GrPath.h"
|
||||||
|
#include "GrStyle.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Verb count limit for generating path key from content of a volatile path.
|
// Verb count limit for generating path key from content of a volatile path.
|
||||||
// The value should accomodate at least simple rects and rrects.
|
// The value should accomodate at least simple rects and rrects.
|
||||||
static const int kSimpleVolatilePathVerbLimit = 10;
|
static const int kSimpleVolatilePathVerbLimit = 10;
|
||||||
|
|
||||||
inline static bool compute_key_for_line_path(const SkPath& path, const GrStrokeInfo& stroke,
|
static inline int style_data_cnt(const GrStyle& style) {
|
||||||
|
int cnt = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||||
|
// This should only fail for an arbitrary path effect, and we should not have gotten
|
||||||
|
// here with anything other than a dash path effect.
|
||||||
|
SkASSERT(cnt >= 0);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write_style_key(uint32_t* dst, const GrStyle& style) {
|
||||||
|
// Pass 1 for the scale since the GPU will apply the style not GrStyle::applyToPath().
|
||||||
|
GrStyle::WriteKey(dst, style, GrStyle::Apply::kPathEffectAndStrokeRec, SK_Scalar1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline static bool compute_key_for_line_path(const SkPath& path, const GrStyle& style,
|
||||||
GrUniqueKey* key) {
|
GrUniqueKey* key) {
|
||||||
SkPoint pts[2];
|
SkPoint pts[2];
|
||||||
if (!path.isLine(pts)) {
|
if (!path.isLine(pts)) {
|
||||||
@ -20,37 +35,37 @@ inline static bool compute_key_for_line_path(const SkPath& path, const GrStrokeI
|
|||||||
}
|
}
|
||||||
static_assert((sizeof(pts) % sizeof(uint32_t)) == 0 && sizeof(pts) > sizeof(uint32_t),
|
static_assert((sizeof(pts) % sizeof(uint32_t)) == 0 && sizeof(pts) > sizeof(uint32_t),
|
||||||
"pts_needs_padding");
|
"pts_needs_padding");
|
||||||
|
int styleDataCnt = style_data_cnt(style);
|
||||||
|
|
||||||
const int kBaseData32Cnt = 1 + sizeof(pts) / sizeof(uint32_t);
|
const int kBaseData32Cnt = 1 + sizeof(pts) / sizeof(uint32_t);
|
||||||
int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
|
|
||||||
static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain();
|
||||||
GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + strokeDataCnt);
|
GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + styleDataCnt);
|
||||||
builder[0] = path.getFillType();
|
builder[0] = path.getFillType();
|
||||||
memcpy(&builder[1], &pts, sizeof(pts));
|
memcpy(&builder[1], &pts, sizeof(pts));
|
||||||
if (strokeDataCnt > 0) {
|
if (styleDataCnt > 0) {
|
||||||
stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]);
|
write_style_key(&builder[kBaseData32Cnt], style);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static bool compute_key_for_oval_path(const SkPath& path, const GrStrokeInfo& stroke,
|
inline static bool compute_key_for_oval_path(const SkPath& path, const GrStyle& style,
|
||||||
GrUniqueKey* key) {
|
GrUniqueKey* key) {
|
||||||
SkRect rect;
|
SkRect rect;
|
||||||
// Point order is significant when dashing, so we cannot devolve to a rect key.
|
// Point order is significant when dashing, so we cannot devolve to a rect key.
|
||||||
if (stroke.isDashed() || !path.isOval(&rect)) {
|
if (style.pathEffect() || !path.isOval(&rect)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static_assert((sizeof(rect) % sizeof(uint32_t)) == 0 && sizeof(rect) > sizeof(uint32_t),
|
static_assert((sizeof(rect) % sizeof(uint32_t)) == 0 && sizeof(rect) > sizeof(uint32_t),
|
||||||
"rect_needs_padding");
|
"rect_needs_padding");
|
||||||
|
|
||||||
const int kBaseData32Cnt = 1 + sizeof(rect) / sizeof(uint32_t);
|
const int kBaseData32Cnt = 1 + sizeof(rect) / sizeof(uint32_t);
|
||||||
int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
|
int styleDataCnt = style_data_cnt(style);
|
||||||
static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain();
|
||||||
GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + strokeDataCnt);
|
GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + styleDataCnt);
|
||||||
builder[0] = path.getFillType();
|
builder[0] = path.getFillType();
|
||||||
memcpy(&builder[1], &rect, sizeof(rect));
|
memcpy(&builder[1], &rect, sizeof(rect));
|
||||||
if (strokeDataCnt > 0) {
|
if (styleDataCnt > 0) {
|
||||||
stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]);
|
write_style_key(&builder[kBaseData32Cnt], style);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -58,7 +73,7 @@ inline static bool compute_key_for_oval_path(const SkPath& path, const GrStrokeI
|
|||||||
// Encodes the full path data to the unique key for very small, volatile paths. This is typically
|
// Encodes the full path data to the unique key for very small, volatile paths. This is typically
|
||||||
// hit when clipping stencils the clip stack. Intention is that this handles rects too, since
|
// hit when clipping stencils the clip stack. Intention is that this handles rects too, since
|
||||||
// SkPath::isRect seems to do non-trivial amount of work.
|
// SkPath::isRect seems to do non-trivial amount of work.
|
||||||
inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrokeInfo& stroke,
|
inline static bool compute_key_for_simple_path(const SkPath& path, const GrStyle& style,
|
||||||
GrUniqueKey* key) {
|
GrUniqueKey* key) {
|
||||||
if (!path.isVolatile()) {
|
if (!path.isVolatile()) {
|
||||||
return false;
|
return false;
|
||||||
@ -109,9 +124,9 @@ inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrok
|
|||||||
// 2) stroke data (varying size)
|
// 2) stroke data (varying size)
|
||||||
|
|
||||||
const int baseData32Cnt = 2 + verbData32Cnt + pointData32Cnt + conicWeightData32Cnt;
|
const int baseData32Cnt = 2 + verbData32Cnt + pointData32Cnt + conicWeightData32Cnt;
|
||||||
const int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
|
const int styleDataCnt = style_data_cnt(style);
|
||||||
static const GrUniqueKey::Domain kSimpleVolatilePathDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kSimpleVolatilePathDomain = GrUniqueKey::GenerateDomain();
|
||||||
GrUniqueKey::Builder builder(key, kSimpleVolatilePathDomain, baseData32Cnt + strokeDataCnt);
|
GrUniqueKey::Builder builder(key, kSimpleVolatilePathDomain, baseData32Cnt + styleDataCnt);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
builder[i++] = path.getFillType();
|
builder[i++] = path.getFillType();
|
||||||
|
|
||||||
@ -153,57 +168,68 @@ inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrok
|
|||||||
SkDEBUGCODE(i += conicWeightData32Cnt);
|
SkDEBUGCODE(i += conicWeightData32Cnt);
|
||||||
}
|
}
|
||||||
SkASSERT(i == baseData32Cnt);
|
SkASSERT(i == baseData32Cnt);
|
||||||
if (strokeDataCnt > 0) {
|
if (styleDataCnt > 0) {
|
||||||
stroke.asUniqueKeyFragment(&builder[baseData32Cnt]);
|
write_style_key(&builder[baseData32Cnt], style);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void compute_key_for_general_path(const SkPath& path, const GrStrokeInfo& stroke,
|
inline static void compute_key_for_general_path(const SkPath& path, const GrStyle& style,
|
||||||
GrUniqueKey* key) {
|
GrUniqueKey* key) {
|
||||||
const int kBaseData32Cnt = 2;
|
const int kBaseData32Cnt = 2;
|
||||||
int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
|
int styleDataCnt = style_data_cnt(style);
|
||||||
static const GrUniqueKey::Domain kGeneralPathDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kGeneralPathDomain = GrUniqueKey::GenerateDomain();
|
||||||
GrUniqueKey::Builder builder(key, kGeneralPathDomain, kBaseData32Cnt + strokeDataCnt);
|
GrUniqueKey::Builder builder(key, kGeneralPathDomain, kBaseData32Cnt + styleDataCnt);
|
||||||
builder[0] = path.getGenerationID();
|
builder[0] = path.getGenerationID();
|
||||||
builder[1] = path.getFillType();
|
builder[1] = path.getFillType();
|
||||||
if (strokeDataCnt > 0) {
|
if (styleDataCnt > 0) {
|
||||||
stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]);
|
write_style_key(&builder[kBaseData32Cnt], style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrPath::ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key,
|
void GrPath::ComputeKey(const SkPath& path, const GrStyle& style, GrUniqueKey* key,
|
||||||
bool* outIsVolatile) {
|
bool* outIsVolatile) {
|
||||||
if (compute_key_for_line_path(path, stroke, key)) {
|
if (compute_key_for_line_path(path, style, key)) {
|
||||||
*outIsVolatile = false;
|
*outIsVolatile = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compute_key_for_oval_path(path, stroke, key)) {
|
if (compute_key_for_oval_path(path, style, key)) {
|
||||||
*outIsVolatile = false;
|
*outIsVolatile = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compute_key_for_simple_path(path, stroke, key)) {
|
if (compute_key_for_simple_path(path, style, key)) {
|
||||||
*outIsVolatile = false;
|
*outIsVolatile = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_key_for_general_path(path, stroke, key);
|
compute_key_for_general_path(path, style, key);
|
||||||
*outIsVolatile = path.isVolatile();
|
*outIsVolatile = path.isVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
bool GrPath::isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const {
|
bool GrPath::isEqualTo(const SkPath& path, const GrStyle& style) const {
|
||||||
if (!fStroke.hasEqualEffect(stroke)) {
|
// Since this is only called in debug we don't care about performance.
|
||||||
|
int cnt0 = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||||
|
int cnt1 = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||||
|
if (cnt0 < 0 || cnt1 < 0 || cnt0 != cnt1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (cnt0) {
|
||||||
|
SkAutoTArray<uint32_t> key0(cnt0);
|
||||||
|
SkAutoTArray<uint32_t> key1(cnt0);
|
||||||
|
write_style_key(key0.get(), fStyle);
|
||||||
|
write_style_key(key1.get(), style);
|
||||||
|
if (0 != memcmp(key0.get(), key1.get(), cnt0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
// We treat same-rect ovals as identical - but only when not dashing.
|
// We treat same-rect ovals as identical - but only when not dashing.
|
||||||
SkRect ovalBounds;
|
SkRect ovalBounds;
|
||||||
if (!fStroke.isDashed() && fSkPath.isOval(&ovalBounds)) {
|
if (!fStyle.isDashed() && fSkPath.isOval(&ovalBounds)) {
|
||||||
SkRect otherOvalBounds;
|
SkRect otherOvalBounds;
|
||||||
return path.isOval(&otherOvalBounds) && ovalBounds == otherOvalBounds;
|
return path.isOval(&otherOvalBounds) && ovalBounds == otherOvalBounds;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#define GrPath_DEFINED
|
#define GrPath_DEFINED
|
||||||
|
|
||||||
#include "GrGpuResource.h"
|
#include "GrGpuResource.h"
|
||||||
#include "GrStrokeInfo.h"
|
|
||||||
#include "GrPathRendering.h"
|
#include "GrPathRendering.h"
|
||||||
|
#include "GrStyle.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
#include "SkRect.h"
|
#include "SkRect.h"
|
||||||
|
|
||||||
@ -19,25 +19,25 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Initialize to a path with a fixed stroke. Stroke must not be hairline.
|
* Initialize to a path with a fixed stroke. Stroke must not be hairline.
|
||||||
*/
|
*/
|
||||||
GrPath(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke)
|
GrPath(GrGpu* gpu, const SkPath& skPath, const GrStyle& style)
|
||||||
: INHERITED(gpu)
|
: INHERITED(gpu)
|
||||||
, fBounds(SkRect::MakeEmpty())
|
, fBounds(SkRect::MakeEmpty())
|
||||||
, fFillType(GrPathRendering::kWinding_FillType)
|
, fFillType(GrPathRendering::kWinding_FillType)
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
, fSkPath(skPath)
|
, fSkPath(skPath)
|
||||||
, fStroke(stroke)
|
, fStyle(style)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key,
|
static void ComputeKey(const SkPath& path, const GrStyle& style, GrUniqueKey* key,
|
||||||
bool* outIsVolatile);
|
bool* outIsVolatile);
|
||||||
|
|
||||||
const SkRect& getBounds() const { return fBounds; }
|
const SkRect& getBounds() const { return fBounds; }
|
||||||
|
|
||||||
GrPathRendering::FillType getFillType() const { return fFillType; }
|
GrPathRendering::FillType getFillType() const { return fFillType; }
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
bool isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const;
|
bool isEqualTo(const SkPath& path, const GrStyle& style) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -46,7 +46,7 @@ protected:
|
|||||||
GrPathRendering::FillType fFillType;
|
GrPathRendering::FillType fFillType;
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
SkPath fSkPath;
|
SkPath fSkPath;
|
||||||
GrStrokeInfo fStroke;
|
GrStyle fStyle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -10,13 +10,12 @@
|
|||||||
|
|
||||||
#include "GrDrawTarget.h"
|
#include "GrDrawTarget.h"
|
||||||
#include "GrStencil.h"
|
#include "GrStencil.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
|
|
||||||
#include "SkDrawProcs.h"
|
#include "SkDrawProcs.h"
|
||||||
#include "SkTArray.h"
|
#include "SkTArray.h"
|
||||||
|
|
||||||
class SkPath;
|
class SkPath;
|
||||||
|
|
||||||
struct GrPoint;
|
struct GrPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,14 +71,14 @@ public:
|
|||||||
* fPipelineBuilder The pipelineBuilder
|
* fPipelineBuilder The pipelineBuilder
|
||||||
* fViewMatrix The viewMatrix
|
* fViewMatrix The viewMatrix
|
||||||
* fPath The path to draw
|
* fPath The path to draw
|
||||||
* fStroke The stroke information (width, join, cap)
|
* fStyle The styling info (path effect, stroking info)
|
||||||
* fAntiAlias True if anti-aliasing is required.
|
* fAntiAlias True if anti-aliasing is required.
|
||||||
*/
|
*/
|
||||||
struct CanDrawPathArgs {
|
struct CanDrawPathArgs {
|
||||||
const GrShaderCaps* fShaderCaps;
|
const GrShaderCaps* fShaderCaps;
|
||||||
const SkMatrix* fViewMatrix;
|
const SkMatrix* fViewMatrix;
|
||||||
const SkPath* fPath;
|
const SkPath* fPath;
|
||||||
const GrStrokeInfo* fStroke;
|
const GrStyle* fStyle;
|
||||||
bool fAntiAlias;
|
bool fAntiAlias;
|
||||||
|
|
||||||
// These next two are only used by GrStencilAndCoverPathRenderer
|
// These next two are only used by GrStencilAndCoverPathRenderer
|
||||||
@ -90,7 +89,7 @@ public:
|
|||||||
SkASSERT(fShaderCaps);
|
SkASSERT(fShaderCaps);
|
||||||
SkASSERT(fViewMatrix);
|
SkASSERT(fViewMatrix);
|
||||||
SkASSERT(fPath);
|
SkASSERT(fPath);
|
||||||
SkASSERT(fStroke);
|
SkASSERT(fStyle);
|
||||||
SkASSERT(!fPath->isEmpty());
|
SkASSERT(!fPath->isEmpty());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -116,7 +115,7 @@ public:
|
|||||||
* fColor Color to render with
|
* fColor Color to render with
|
||||||
* fViewMatrix The viewMatrix
|
* fViewMatrix The viewMatrix
|
||||||
* fPath the path to draw.
|
* fPath the path to draw.
|
||||||
* fStroke the stroke information (width, join, cap)
|
* fStyle the style information (path effect, stroke info)
|
||||||
* fAntiAlias true if anti-aliasing is required.
|
* fAntiAlias true if anti-aliasing is required.
|
||||||
* fGammaCorrect true if gamma-correct rendering is to be used.
|
* fGammaCorrect true if gamma-correct rendering is to be used.
|
||||||
*/
|
*/
|
||||||
@ -127,7 +126,7 @@ public:
|
|||||||
GrColor fColor;
|
GrColor fColor;
|
||||||
const SkMatrix* fViewMatrix;
|
const SkMatrix* fViewMatrix;
|
||||||
const SkPath* fPath;
|
const SkPath* fPath;
|
||||||
const GrStrokeInfo* fStroke;
|
const GrStyle* fStyle;
|
||||||
bool fAntiAlias;
|
bool fAntiAlias;
|
||||||
bool fGammaCorrect;
|
bool fGammaCorrect;
|
||||||
|
|
||||||
@ -137,7 +136,7 @@ public:
|
|||||||
SkASSERT(fPipelineBuilder);
|
SkASSERT(fPipelineBuilder);
|
||||||
SkASSERT(fViewMatrix);
|
SkASSERT(fViewMatrix);
|
||||||
SkASSERT(fPath);
|
SkASSERT(fPath);
|
||||||
SkASSERT(fStroke);
|
SkASSERT(fStyle);
|
||||||
SkASSERT(!fPath->isEmpty());
|
SkASSERT(!fPath->isEmpty());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -153,7 +152,7 @@ public:
|
|||||||
canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps();
|
canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps();
|
||||||
canArgs.fViewMatrix = args.fViewMatrix;
|
canArgs.fViewMatrix = args.fViewMatrix;
|
||||||
canArgs.fPath = args.fPath;
|
canArgs.fPath = args.fPath;
|
||||||
canArgs.fStroke = args.fStroke;
|
canArgs.fStyle = args.fStyle;
|
||||||
canArgs.fAntiAlias = args.fAntiAlias;
|
canArgs.fAntiAlias = args.fAntiAlias;
|
||||||
|
|
||||||
canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
|
canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
|
||||||
@ -162,8 +161,7 @@ public:
|
|||||||
SkASSERT(this->canDrawPath(canArgs));
|
SkASSERT(this->canDrawPath(canArgs));
|
||||||
if (!args.fPipelineBuilder->getStencil().isDisabled()) {
|
if (!args.fPipelineBuilder->getStencil().isDisabled()) {
|
||||||
SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath));
|
SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath));
|
||||||
SkASSERT(!args.fStroke->isDashed());
|
SkASSERT(args.fStyle->isSimpleFill());
|
||||||
SkASSERT(args.fStroke->isFillStyle());
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return this->onDrawPath(args);
|
return this->onDrawPath(args);
|
||||||
@ -197,22 +195,21 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Draws the path to the stencil buffer. Assume the writable stencil bits are already
|
* Draws the path to the stencil buffer. Assume the writable stencil bits are already
|
||||||
* initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
|
* initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void stencilPath(const StencilPathArgs& args) {
|
void stencilPath(const StencilPathArgs& args) {
|
||||||
SkDEBUGCODE(args.validate();)
|
SkDEBUGCODE(args.validate();)
|
||||||
SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fPath));
|
SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fPath));
|
||||||
|
|
||||||
this->onStencilPath(args);
|
this->onStencilPath(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
|
// Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
|
||||||
// If we can, we draw lots faster (raster device does this same test).
|
// If we can, we draw lots faster (raster device does this same test).
|
||||||
static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
|
static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
|
||||||
SkScalar* outCoverage) {
|
SkScalar* outCoverage) {
|
||||||
if (stroke.isDashed()) {
|
if (style.pathEffect()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const SkStrokeRec& stroke = style.strokeRec();
|
||||||
if (stroke.isHairlineStyle()) {
|
if (stroke.isHairlineStyle()) {
|
||||||
if (outCoverage) {
|
if (outCoverage) {
|
||||||
*outCoverage = SK_Scalar1;
|
*outCoverage = SK_Scalar1;
|
||||||
@ -279,13 +276,12 @@ private:
|
|||||||
drawArgs.fColor = 0xFFFFFFFF;
|
drawArgs.fColor = 0xFFFFFFFF;
|
||||||
drawArgs.fViewMatrix = args.fViewMatrix;
|
drawArgs.fViewMatrix = args.fViewMatrix;
|
||||||
drawArgs.fPath = args.fPath;
|
drawArgs.fPath = args.fPath;
|
||||||
drawArgs.fStroke = &GrStrokeInfo::FillInfo();
|
drawArgs.fStyle = &GrStyle::SimpleFill();
|
||||||
drawArgs.fAntiAlias = false;
|
drawArgs.fAntiAlias = false;
|
||||||
drawArgs.fGammaCorrect = false;
|
drawArgs.fGammaCorrect = false;
|
||||||
this->drawPath(drawArgs);
|
this->drawPath(drawArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef SkRefCnt INHERITED;
|
typedef SkRefCnt INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer(
|
|||||||
}
|
}
|
||||||
if (minStencilSupport != GrPathRenderer::kNoSupport_StencilSupport) {
|
if (minStencilSupport != GrPathRenderer::kNoSupport_StencilSupport) {
|
||||||
// We don't support (and shouldn't need) stenciling of non-fill paths.
|
// We don't support (and shouldn't need) stenciling of non-fill paths.
|
||||||
if (!args.fStroke->isFillStyle() || args.fStroke->isDashed()) {
|
if (!args.fStyle->isSimpleFill()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ private:
|
|||||||
GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
|
GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
|
||||||
const SkScalerContextEffects& effects,
|
const SkScalerContextEffects& effects,
|
||||||
const SkDescriptor* desc,
|
const SkDescriptor* desc,
|
||||||
const GrStrokeInfo& stroke) {
|
const GrStyle& style) {
|
||||||
if (nullptr == typeface) {
|
if (nullptr == typeface) {
|
||||||
typeface = SkTypeface::GetDefaultTypeface();
|
typeface = SkTypeface::GetDefaultTypeface();
|
||||||
SkASSERT(nullptr != typeface);
|
SkASSERT(nullptr != typeface);
|
||||||
@ -62,7 +62,7 @@ GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
|
|||||||
|
|
||||||
if (desc) {
|
if (desc) {
|
||||||
SkAutoTUnref<GlyphGenerator> generator(new GlyphGenerator(*typeface, effects, *desc));
|
SkAutoTUnref<GlyphGenerator> generator(new GlyphGenerator(*typeface, effects, *desc));
|
||||||
return this->createPathRange(generator, stroke);
|
return this->createPathRange(generator, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkScalerContextRec rec;
|
SkScalerContextRec rec;
|
||||||
@ -83,5 +83,5 @@ GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
|
|||||||
SkScalerContextEffects noEffects;
|
SkScalerContextEffects noEffects;
|
||||||
|
|
||||||
SkAutoTUnref<GlyphGenerator> generator(new GlyphGenerator(*typeface, noEffects, *genericDesc));
|
SkAutoTUnref<GlyphGenerator> generator(new GlyphGenerator(*typeface, noEffects, *genericDesc));
|
||||||
return this->createPathRange(generator, stroke);
|
return this->createPathRange(generator, style);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class SkDescriptor;
|
|||||||
class SkTypeface;
|
class SkTypeface;
|
||||||
class GrPath;
|
class GrPath;
|
||||||
class GrStencilSettings;
|
class GrStencilSettings;
|
||||||
class GrStrokeInfo;
|
class GrStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class wrapping HW path rendering API.
|
* Abstract class wrapping HW path rendering API.
|
||||||
@ -81,21 +81,23 @@ public:
|
|||||||
* Creates a new gpu path, based on the specified path and stroke and returns it.
|
* Creates a new gpu path, based on the specified path and stroke and returns it.
|
||||||
* The caller owns a ref on the returned path which must be balanced by a call to unref.
|
* The caller owns a ref on the returned path which must be balanced by a call to unref.
|
||||||
*
|
*
|
||||||
* @param skPath the path geometry.
|
* @param SkPath the geometry.
|
||||||
* @param stroke the path stroke.
|
* @param GrStyle the style applied to the path. Styles with non-dash path effects are not
|
||||||
* @return a new path.
|
* allowed.
|
||||||
|
* @return a new GPU path object.
|
||||||
*/
|
*/
|
||||||
virtual GrPath* createPath(const SkPath&, const GrStrokeInfo&) = 0;
|
virtual GrPath* createPath(const SkPath&, const GrStyle&) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a range of gpu paths with a common stroke. The caller owns a ref on the
|
* Creates a range of gpu paths with a common style. The caller owns a ref on the
|
||||||
* returned path range which must be balanced by a call to unref.
|
* returned path range which must be balanced by a call to unref.
|
||||||
*
|
*
|
||||||
* @param PathGenerator class that generates SkPath objects for each path in the range.
|
* @param PathGenerator class that generates SkPath objects for each path in the range.
|
||||||
* @param GrStrokeInfo the common stroke applied to each path in the range.
|
* @param GrStyle the common style applied to each path in the range. Styles with non-dash
|
||||||
|
* path effects are not allowed.
|
||||||
* @return a new path range.
|
* @return a new path range.
|
||||||
*/
|
*/
|
||||||
virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&) = 0;
|
virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStyle&) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a range of glyph paths, indexed by glyph id. The glyphs will have an
|
* Creates a range of glyph paths, indexed by glyph id. The glyphs will have an
|
||||||
@ -118,15 +120,15 @@ public:
|
|||||||
* including with the stroke information baked directly into
|
* including with the stroke information baked directly into
|
||||||
* the outlines.
|
* the outlines.
|
||||||
*
|
*
|
||||||
* @param GrStrokeInfo Common stroke that the GPU will apply to every path. Note that
|
* @param GrStyle Common style that the GPU will apply to every path. Note that
|
||||||
* if the glyph outlines contain baked-in strokes from the font
|
* if the glyph outlines contain baked-in styles from the font
|
||||||
* descriptor, the GPU stroke will be applied on top of those
|
* descriptor, the GPU style will be applied on top of those
|
||||||
* outlines.
|
* outlines.
|
||||||
*
|
*
|
||||||
* @return a new path range populated with glyphs.
|
* @return a new path range populated with glyphs.
|
||||||
*/
|
*/
|
||||||
GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&,
|
GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&,
|
||||||
const SkDescriptor*, const GrStrokeInfo&);
|
const SkDescriptor*, const GrStyle&);
|
||||||
|
|
||||||
/** None of these params are optional, pointers used just to avoid making copies. */
|
/** None of these params are optional, pointers used just to avoid making copies. */
|
||||||
struct StencilPathArgs {
|
struct StencilPathArgs {
|
||||||
|
@ -70,24 +70,24 @@ const GrBuffer* GrResourceProvider::createQuadIndexBuffer() {
|
|||||||
return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
|
return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStrokeInfo& stroke) {
|
GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
|
||||||
SkASSERT(this->gpu()->pathRendering());
|
SkASSERT(this->gpu()->pathRendering());
|
||||||
return this->gpu()->pathRendering()->createPath(path, stroke);
|
return this->gpu()->pathRendering()->createPath(path, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
|
GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
|
||||||
const GrStrokeInfo& stroke) {
|
const GrStyle& style) {
|
||||||
SkASSERT(this->gpu()->pathRendering());
|
SkASSERT(this->gpu()->pathRendering());
|
||||||
return this->gpu()->pathRendering()->createPathRange(gen, stroke);
|
return this->gpu()->pathRendering()->createPathRange(gen, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
|
GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
|
||||||
const SkScalerContextEffects& effects,
|
const SkScalerContextEffects& effects,
|
||||||
const SkDescriptor* desc,
|
const SkDescriptor* desc,
|
||||||
const GrStrokeInfo& stroke) {
|
const GrStyle& style) {
|
||||||
|
|
||||||
SkASSERT(this->gpu()->pathRendering());
|
SkASSERT(this->gpu()->pathRendering());
|
||||||
return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, stroke);
|
return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
|
GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
|
||||||
|
@ -18,7 +18,7 @@ class GrPath;
|
|||||||
class GrRenderTarget;
|
class GrRenderTarget;
|
||||||
class GrSingleOwner;
|
class GrSingleOwner;
|
||||||
class GrStencilAttachment;
|
class GrStencilAttachment;
|
||||||
class GrStrokeInfo;
|
class GrStyle;
|
||||||
class SkDescriptor;
|
class SkDescriptor;
|
||||||
class SkPath;
|
class SkPath;
|
||||||
class SkTypeface;
|
class SkTypeface;
|
||||||
@ -83,10 +83,10 @@ public:
|
|||||||
* Factories for GrPath and GrPathRange objects. It's an error to call these if path rendering
|
* Factories for GrPath and GrPathRange objects. It's an error to call these if path rendering
|
||||||
* is not supported.
|
* is not supported.
|
||||||
*/
|
*/
|
||||||
GrPath* createPath(const SkPath&, const GrStrokeInfo&);
|
GrPath* createPath(const SkPath&, const GrStyle&);
|
||||||
GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&);
|
GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStyle&);
|
||||||
GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&,
|
GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&,
|
||||||
const SkDescriptor*, const GrStrokeInfo&);
|
const SkDescriptor*, const GrStyle&);
|
||||||
|
|
||||||
using GrTextureProvider::assignUniqueKeyToResource;
|
using GrTextureProvider::assignUniqueKeyToResource;
|
||||||
using GrTextureProvider::findAndRefResourceByUniqueKey;
|
using GrTextureProvider::findAndRefResourceByUniqueKey;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "GrDrawTarget.h"
|
#include "GrDrawTarget.h"
|
||||||
#include "GrGpu.h"
|
#include "GrGpu.h"
|
||||||
#include "GrPipelineBuilder.h"
|
#include "GrPipelineBuilder.h"
|
||||||
|
#include "GrStyle.h"
|
||||||
|
|
||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
#include "SkDistanceFieldGen.h"
|
#include "SkDistanceFieldGen.h"
|
||||||
@ -117,22 +118,11 @@ void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
|
|||||||
/**
|
/**
|
||||||
* Draw a single path element of the clip stack into the accumulation bitmap
|
* Draw a single path element of the clip stack into the accumulation bitmap
|
||||||
*/
|
*/
|
||||||
void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
|
void GrSWMaskHelper::draw(const SkPath& path, const GrStyle& style, SkRegion::Op op,
|
||||||
bool antiAlias, uint8_t alpha) {
|
bool antiAlias, uint8_t alpha) {
|
||||||
|
|
||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
if (stroke.isHairlineStyle()) {
|
paint.setPathEffect(sk_ref_sp(style.pathEffect()));
|
||||||
paint.setStyle(SkPaint::kStroke_Style);
|
style.strokeRec().applyToPaint(&paint);
|
||||||
} else {
|
|
||||||
if (stroke.isFillStyle()) {
|
|
||||||
paint.setStyle(SkPaint::kFill_Style);
|
|
||||||
} else {
|
|
||||||
paint.setStyle(SkPaint::kStroke_Style);
|
|
||||||
paint.setStrokeJoin(stroke.getJoin());
|
|
||||||
paint.setStrokeCap(stroke.getCap());
|
|
||||||
paint.setStrokeWidth(stroke.getWidth());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
paint.setAntiAlias(antiAlias);
|
paint.setAntiAlias(antiAlias);
|
||||||
|
|
||||||
SkTBlitterAllocator allocator;
|
SkTBlitterAllocator allocator;
|
||||||
@ -307,7 +297,7 @@ void GrSWMaskHelper::toSDF(unsigned char* sdf) {
|
|||||||
*/
|
*/
|
||||||
GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
|
GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const SkStrokeRec& stroke,
|
const GrStyle& style,
|
||||||
const SkIRect& resultBounds,
|
const SkIRect& resultBounds,
|
||||||
bool antiAlias,
|
bool antiAlias,
|
||||||
const SkMatrix* matrix) {
|
const SkMatrix* matrix) {
|
||||||
@ -317,7 +307,7 @@ GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
|
helper.draw(path, style, SkRegion::kReplace_Op, antiAlias, 0xFF);
|
||||||
|
|
||||||
GrTexture* texture(helper.createTexture());
|
GrTexture* texture(helper.createTexture());
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
|
@ -55,11 +55,10 @@ public:
|
|||||||
bool init(const SkIRect& resultBounds, const SkMatrix* matrix, bool allowCompression = true);
|
bool init(const SkIRect& resultBounds, const SkMatrix* matrix, bool allowCompression = true);
|
||||||
|
|
||||||
// Draw a single rect into the accumulation bitmap using the specified op
|
// Draw a single rect into the accumulation bitmap using the specified op
|
||||||
void draw(const SkRect& rect, SkRegion::Op op,
|
void draw(const SkRect& rect, SkRegion::Op op, bool antiAlias, uint8_t alpha);
|
||||||
bool antiAlias, uint8_t alpha);
|
|
||||||
|
|
||||||
// Draw a single path into the accumuation bitmap using the specified op
|
// Draw a single path into the accumuation bitmap using the specified op
|
||||||
void draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
|
void draw(const SkPath& path, const GrStyle& style, SkRegion::Op op,
|
||||||
bool antiAlias, uint8_t alpha);
|
bool antiAlias, uint8_t alpha);
|
||||||
|
|
||||||
// Move the mask generation results from the internal bitmap to the gpu.
|
// Move the mask generation results from the internal bitmap to the gpu.
|
||||||
@ -77,7 +76,7 @@ public:
|
|||||||
// to the GPU. The result is returned.
|
// to the GPU. The result is returned.
|
||||||
static GrTexture* DrawPathMaskToTexture(GrContext* context,
|
static GrTexture* DrawPathMaskToTexture(GrContext* context,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const SkStrokeRec& stroke,
|
const GrStyle& style,
|
||||||
const SkIRect& resultBounds,
|
const SkIRect& resultBounds,
|
||||||
bool antiAlias,
|
bool antiAlias,
|
||||||
const SkMatrix* matrix);
|
const SkMatrix* matrix);
|
||||||
|
@ -12,13 +12,7 @@
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
if (nullptr == fContext) {
|
return SkToBool(fContext);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (args.fStroke->isDashed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -130,7 +124,7 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkAutoTUnref<GrTexture> texture(
|
SkAutoTUnref<GrTexture> texture(
|
||||||
GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStroke,
|
GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStyle,
|
||||||
devPathBounds,
|
devPathBounds,
|
||||||
args.fAntiAlias, args.fViewMatrix));
|
args.fAntiAlias, args.fViewMatrix));
|
||||||
if (nullptr == texture) {
|
if (nullptr == texture) {
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "GrStrokeInfo.h"
|
|
||||||
#include "GrResourceKey.h"
|
|
||||||
#include "SkDashPathPriv.h"
|
|
||||||
|
|
||||||
bool all_dash_intervals_zero(const SkScalar* intervals, int count) {
|
|
||||||
for (int i = 0 ; i < count; ++i) {
|
|
||||||
if (intervals[i] != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GrStrokeInfo::applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo,
|
|
||||||
const SkPath& src) const {
|
|
||||||
if (this->isDashed()) {
|
|
||||||
SkPathEffect::DashInfo info;
|
|
||||||
info.fIntervals = fIntervals.get();
|
|
||||||
info.fCount = fIntervals.count();
|
|
||||||
info.fPhase = fDashPhase;
|
|
||||||
GrStrokeInfo filteredStroke(*this, false);
|
|
||||||
// Handle the case where all intervals are 0 and we simply drop the dash effect
|
|
||||||
if (all_dash_intervals_zero(fIntervals.get(), fIntervals.count())) {
|
|
||||||
*dstStrokeInfo = filteredStroke;
|
|
||||||
*dst = src;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// See if we can filter the dash into a path on cpu
|
|
||||||
if (SkDashPath::FilterDashPath(dst, src, &filteredStroke, nullptr, info)) {
|
|
||||||
*dstStrokeInfo = filteredStroke;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrStrokeInfo::asUniqueKeyFragment(uint32_t* data) const {
|
|
||||||
const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
|
|
||||||
enum {
|
|
||||||
kStyleBits = 2,
|
|
||||||
kJoinBits = 2,
|
|
||||||
kCapBits = 32 - kStyleBits - kJoinBits,
|
|
||||||
|
|
||||||
kJoinShift = kStyleBits,
|
|
||||||
kCapShift = kJoinShift + kJoinBits,
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(SkStrokeRec::kStyleCount <= (1 << kStyleBits), "style_shift_will_be_wrong");
|
|
||||||
static_assert(SkPaint::kJoinCount <= (1 << kJoinBits), "cap_shift_will_be_wrong");
|
|
||||||
static_assert(SkPaint::kCapCount <= (1 << kCapBits), "cap_does_not_fit");
|
|
||||||
uint32_t styleKey = this->getStyle();
|
|
||||||
if (this->needToApply()) {
|
|
||||||
styleKey |= this->getJoin() << kJoinShift;
|
|
||||||
styleKey |= this->getCap() << kCapShift;
|
|
||||||
}
|
|
||||||
int i = 0;
|
|
||||||
data[i++] = styleKey;
|
|
||||||
|
|
||||||
// Memcpy the scalar fields. Does not "reinterpret_cast<SkScalar&>(data[i]) = ..." due to
|
|
||||||
// scalars having more strict alignment requirements than what data can guarantee. The
|
|
||||||
// compiler should optimize memcpys to assignments.
|
|
||||||
SkScalar scalar;
|
|
||||||
scalar = this->getMiter();
|
|
||||||
memcpy(&data[i], &scalar, sizeof(scalar));
|
|
||||||
i += kSkScalarData32Cnt;
|
|
||||||
|
|
||||||
scalar = this->getWidth();
|
|
||||||
memcpy(&data[i], &scalar, sizeof(scalar));
|
|
||||||
i += kSkScalarData32Cnt;
|
|
||||||
|
|
||||||
if (this->isDashed()) {
|
|
||||||
SkScalar phase = this->getDashPhase();
|
|
||||||
memcpy(&data[i], &phase, sizeof(phase));
|
|
||||||
i += kSkScalarData32Cnt;
|
|
||||||
|
|
||||||
int32_t count = this->getDashCount() & static_cast<int32_t>(~1);
|
|
||||||
SkASSERT(count == this->getDashCount());
|
|
||||||
const SkScalar* intervals = this->getDashIntervals();
|
|
||||||
int intervalByteCnt = count * sizeof(SkScalar);
|
|
||||||
memcpy(&data[i], intervals, intervalByteCnt);
|
|
||||||
// Enable the line below if fields are added after dashing.
|
|
||||||
SkDEBUGCODE(i += kSkScalarData32Cnt * count);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkASSERT(this->computeUniqueKeyFragmentData32Cnt() == i);
|
|
||||||
}
|
|
@ -1,191 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GrStrokeInfo_DEFINED
|
|
||||||
#define GrStrokeInfo_DEFINED
|
|
||||||
|
|
||||||
#include "SkPathEffect.h"
|
|
||||||
#include "SkStrokeRec.h"
|
|
||||||
#include "SkTemplates.h"
|
|
||||||
|
|
||||||
class GrUniqueKey;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec
|
|
||||||
* which holds information on fill style, width, miter, cap, and join. It also holds information
|
|
||||||
* about the dash like intervals, count, and phase.
|
|
||||||
*/
|
|
||||||
class GrStrokeInfo : public SkStrokeRec {
|
|
||||||
public:
|
|
||||||
static const GrStrokeInfo& FillInfo() {
|
|
||||||
static const GrStrokeInfo gFill(kFill_InitStyle);
|
|
||||||
return gFill;
|
|
||||||
}
|
|
||||||
|
|
||||||
GrStrokeInfo(SkStrokeRec::InitStyle style)
|
|
||||||
: INHERITED(style)
|
|
||||||
, fDashType(SkPathEffect::kNone_DashType) {
|
|
||||||
}
|
|
||||||
|
|
||||||
GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true)
|
|
||||||
: INHERITED(src) {
|
|
||||||
if (includeDash && src.isDashed()) {
|
|
||||||
fDashType = src.fDashType;
|
|
||||||
fDashPhase = src.fDashPhase;
|
|
||||||
fIntervals.reset(src.getDashCount());
|
|
||||||
memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
|
|
||||||
} else {
|
|
||||||
fDashType = SkPathEffect::kNone_DashType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride)
|
|
||||||
: INHERITED(paint, styleOverride)
|
|
||||||
, fDashType(SkPathEffect::kNone_DashType) {
|
|
||||||
this->init(paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit GrStrokeInfo(const SkPaint& paint)
|
|
||||||
: INHERITED(paint)
|
|
||||||
, fDashType(SkPathEffect::kNone_DashType) {
|
|
||||||
this->init(paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
GrStrokeInfo& operator=(const GrStrokeInfo& other) {
|
|
||||||
if (other.isDashed()) {
|
|
||||||
fDashType = other.fDashType;
|
|
||||||
fDashPhase = other.fDashPhase;
|
|
||||||
fIntervals.reset(other.getDashCount());
|
|
||||||
memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
|
|
||||||
} else {
|
|
||||||
this->removeDash();
|
|
||||||
}
|
|
||||||
this->INHERITED::operator=(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasEqualEffect(const GrStrokeInfo& other) const {
|
|
||||||
if (this->isDashed() != other.isDashed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this->isDashed()) {
|
|
||||||
if (fDashPhase != other.fDashPhase ||
|
|
||||||
fIntervals.count() != other.fIntervals.count() ||
|
|
||||||
memcmp(fIntervals.get(), other.fIntervals.get(),
|
|
||||||
fIntervals.count() * sizeof(SkScalar)) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this->INHERITED::hasEqualEffect(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This functions takes in a patheffect and updates the dashing information if the path effect
|
|
||||||
* is a Dash type. Returns true if the path effect is a dashed effect and we are stroking,
|
|
||||||
* otherwise it returns false.
|
|
||||||
*/
|
|
||||||
bool setDashInfo(const SkPathEffect* pe) {
|
|
||||||
if (pe && !this->isFillStyle()) {
|
|
||||||
SkPathEffect::DashInfo dashInfo;
|
|
||||||
fDashType = pe->asADash(&dashInfo);
|
|
||||||
if (SkPathEffect::kDash_DashType == fDashType) {
|
|
||||||
fIntervals.reset(dashInfo.fCount);
|
|
||||||
dashInfo.fIntervals = fIntervals.get();
|
|
||||||
pe->asADash(&dashInfo);
|
|
||||||
fDashPhase = dashInfo.fPhase;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Like the above, but sets with an explicit SkPathEffect::DashInfo
|
|
||||||
*/
|
|
||||||
bool setDashInfo(const SkPathEffect::DashInfo& info) {
|
|
||||||
if (!this->isFillStyle()) {
|
|
||||||
fDashType = SkPathEffect::kDash_DashType;
|
|
||||||
fDashPhase = info.fPhase;
|
|
||||||
fIntervals.reset(info.fCount);
|
|
||||||
for (int i = 0; i < fIntervals.count(); i++) {
|
|
||||||
fIntervals[i] = info.fIntervals[i];
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDashed() const {
|
|
||||||
return (!this->isFillStyle() && SkPathEffect::kDash_DashType == fDashType);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t getDashCount() const {
|
|
||||||
SkASSERT(this->isDashed());
|
|
||||||
return fIntervals.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
SkScalar getDashPhase() const {
|
|
||||||
SkASSERT(this->isDashed());
|
|
||||||
return fDashPhase;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkScalar* getDashIntervals() const {
|
|
||||||
SkASSERT(this->isDashed());
|
|
||||||
return fIntervals.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeDash() {
|
|
||||||
fDashType = SkPathEffect::kNone_DashType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Applies the dash to a path, if the stroke info has dashing.
|
|
||||||
* @return true if the dashing was applied (dst and dstStrokeInfo will be modified).
|
|
||||||
* false if the stroke info did not have dashing. The dst and dstStrokeInfo
|
|
||||||
* will be unmodified. The stroking in the SkStrokeRec might still
|
|
||||||
* be applicable.
|
|
||||||
*/
|
|
||||||
bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the length of the data that will be written by asUniqueKeyFragment() function.
|
|
||||||
*/
|
|
||||||
int computeUniqueKeyFragmentData32Cnt() const {
|
|
||||||
const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
|
|
||||||
// SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width.
|
|
||||||
int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt;
|
|
||||||
|
|
||||||
if (this->isDashed()) {
|
|
||||||
// One scalar for dash phase and one for each dash value.
|
|
||||||
strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt;
|
|
||||||
}
|
|
||||||
return strokeKeyData32Cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the object contents as uint32_t data, to be used with GrUniqueKey.
|
|
||||||
* Note: the data written does not encode the length, so care must be taken to ensure
|
|
||||||
* that the full unique key data is encoded properly. For example, GrStrokeInfo
|
|
||||||
* fragment can be placed last in the sequence, at fixed index.
|
|
||||||
*/
|
|
||||||
void asUniqueKeyFragment(uint32_t*) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect.
|
|
||||||
bool hasEqualEffect(const SkStrokeRec& other) const;
|
|
||||||
|
|
||||||
void init(const SkPaint& paint) {
|
|
||||||
const SkPathEffect* pe = paint.getPathEffect();
|
|
||||||
this->setDashInfo(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkPathEffect::DashType fDashType;
|
|
||||||
SkScalar fDashPhase;
|
|
||||||
SkAutoSTArray<2, SkScalar> fIntervals;
|
|
||||||
typedef SkStrokeRec INHERITED;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -85,6 +85,11 @@ public:
|
|||||||
this->initPathEffect(paint.getPathEffect());
|
this->initPathEffect(paint.getPathEffect());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit GrStyle(const SkPaint& paint, SkPaint::Style overrideStyle)
|
||||||
|
: fStrokeRec(paint, overrideStyle) {
|
||||||
|
this->initPathEffect(paint.getPathEffect());
|
||||||
|
}
|
||||||
|
|
||||||
GrStyle& operator=(const GrStyle& that) {
|
GrStyle& operator=(const GrStyle& that) {
|
||||||
fPathEffect = that.fPathEffect;
|
fPathEffect = that.fPathEffect;
|
||||||
fDashInfo = that.fDashInfo;
|
fDashInfo = that.fDashInfo;
|
||||||
@ -133,6 +138,12 @@ public:
|
|||||||
return this->pathEffect() || (!fStrokeRec.isFillStyle() && !fStrokeRec.isHairlineStyle());
|
return this->pathEffect() || (!fStrokeRec.isFillStyle() && !fStrokeRec.isHairlineStyle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SkScalar MatrixToScaleFactor(const SkMatrix& matrix) {
|
||||||
|
// getMaxScale will return -1 if the matrix has perspective. In that case we can use a scale
|
||||||
|
// factor of 1. This isn't necessarily a good choice and in the future we might consider
|
||||||
|
// taking a bounds here for the perspective case.
|
||||||
|
return SkScalarAbs(matrix.getMaxScale());
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Applies just the path effect and returns remaining stroke information. This will fail if
|
* Applies just the path effect and returns remaining stroke information. This will fail if
|
||||||
* there is no path effect. dst may or may not have been overwritten on failure. Scale controls
|
* there is no path effect. dst may or may not have been overwritten on failure. Scale controls
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "GrStrokeInfo.h"
|
|
||||||
#include "GrTestUtils.h"
|
#include "GrTestUtils.h"
|
||||||
|
#include "GrStyle.h"
|
||||||
|
#include "SkDashPathPriv.h"
|
||||||
#include "SkMatrix.h"
|
#include "SkMatrix.h"
|
||||||
#include "SkPathEffect.h"
|
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
#include "SkRRect.h"
|
#include "SkRRect.h"
|
||||||
|
|
||||||
@ -237,26 +237,53 @@ SkStrokeRec TestStrokeRec(SkRandom* random) {
|
|||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrStrokeInfo TestStrokeInfo(SkRandom* random) {
|
void TestStyle(SkRandom* random, GrStyle* style) {
|
||||||
SkStrokeRec::InitStyle style =
|
SkStrokeRec::InitStyle initStyle =
|
||||||
SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
|
SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
|
||||||
GrStrokeInfo strokeInfo(style);
|
SkStrokeRec stroke(initStyle);
|
||||||
randomize_stroke_rec(&strokeInfo, random);
|
randomize_stroke_rec(&stroke, random);
|
||||||
SkPathEffect::DashInfo dashInfo;
|
sk_sp<SkPathEffect> pe;
|
||||||
dashInfo.fCount = random->nextRangeU(1, 50) * 2;
|
if (random->nextBool()) {
|
||||||
dashInfo.fIntervals = new SkScalar[dashInfo.fCount];
|
int cnt = random->nextRangeU(1, 50) * 2;
|
||||||
|
SkAutoTDeleteArray<SkScalar> intervals(new SkScalar[cnt]);
|
||||||
SkScalar sum = 0;
|
SkScalar sum = 0;
|
||||||
for (int i = 0; i < dashInfo.fCount; i++) {
|
for (int i = 0; i < cnt; i++) {
|
||||||
dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
|
intervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
|
||||||
SkDoubleToScalar(10.0));
|
SkDoubleToScalar(10.0));
|
||||||
sum += dashInfo.fIntervals[i];
|
sum += intervals[i];
|
||||||
}
|
}
|
||||||
dashInfo.fPhase = random->nextRangeScalar(0, sum);
|
SkScalar phase = random->nextRangeScalar(0, sum);
|
||||||
strokeInfo.setDashInfo(dashInfo);
|
pe = TestDashPathEffect::Make(intervals.get(), cnt, phase);
|
||||||
delete[] dashInfo.fIntervals;
|
}
|
||||||
return strokeInfo;
|
*style = GrStyle(stroke, pe.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
TestDashPathEffect::TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase) {
|
||||||
|
fCount = count;
|
||||||
|
fIntervals.reset(count);
|
||||||
|
memcpy(fIntervals.get(), intervals, count * sizeof(SkScalar));
|
||||||
|
SkDashPath::CalcDashParameters(phase, intervals, count, &fInitialDashLength,
|
||||||
|
&fInitialDashIndex, &fIntervalLength, &fPhase);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
|
||||||
|
const SkRect* cullRect) const {
|
||||||
|
return SkDashPath::InternalFilter(dst, src, rec, cullRect, fIntervals.get(), fCount,
|
||||||
|
fInitialDashLength, fInitialDashIndex, fIntervalLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPathEffect::DashType TestDashPathEffect::asADash(DashInfo* info) const {
|
||||||
|
if (info) {
|
||||||
|
if (info->fCount >= fCount && info->fIntervals) {
|
||||||
|
memcpy(info->fIntervals, fIntervals.get(), fCount * sizeof(SkScalar));
|
||||||
|
}
|
||||||
|
info->fCount = fCount;
|
||||||
|
info->fPhase = fPhase;
|
||||||
|
}
|
||||||
|
return kDash_DashType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace GrTest
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include "GrImageIDTextureAdjuster.h"
|
#include "GrImageIDTextureAdjuster.h"
|
||||||
#include "GrLayerHoister.h"
|
#include "GrLayerHoister.h"
|
||||||
#include "GrRecordReplaceDraw.h"
|
#include "GrRecordReplaceDraw.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "GrTracing.h"
|
#include "GrTracing.h"
|
||||||
#include "SkCanvasPriv.h"
|
#include "SkCanvasPriv.h"
|
||||||
#include "SkErrorInternals.h"
|
#include "SkErrorInternals.h"
|
||||||
@ -454,7 +454,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
|
if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
|
||||||
GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
|
GrStyle style(paint, SkPaint::kStroke_Style);
|
||||||
GrPaint grPaint;
|
GrPaint grPaint;
|
||||||
if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
|
if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
|
||||||
this->surfaceProps().isGammaCorrect(), &grPaint)) {
|
this->surfaceProps().isGammaCorrect(), &grPaint)) {
|
||||||
@ -464,7 +464,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
|
|||||||
path.setIsVolatile(true);
|
path.setIsVolatile(true);
|
||||||
path.moveTo(pts[0]);
|
path.moveTo(pts[0]);
|
||||||
path.lineTo(pts[1]);
|
path.lineTo(pts[1]);
|
||||||
fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, strokeInfo);
|
fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, style);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,9 +535,8 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrStrokeInfo strokeInfo(paint);
|
GrStyle style(paint);
|
||||||
|
fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &style);
|
||||||
fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -554,7 +553,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrStrokeInfo strokeInfo(paint);
|
GrStyle style(paint);
|
||||||
if (paint.getMaskFilter()) {
|
if (paint.getMaskFilter()) {
|
||||||
// try to hit the fast path for drawing filtered round rects
|
// try to hit the fast path for drawing filtered round rects
|
||||||
|
|
||||||
@ -577,7 +576,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
|
|||||||
&grPaint,
|
&grPaint,
|
||||||
fClip,
|
fClip,
|
||||||
*draw.fMatrix,
|
*draw.fMatrix,
|
||||||
strokeInfo,
|
style.strokeRec(),
|
||||||
devRRect)) {
|
devRRect)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -587,7 +586,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paint.getMaskFilter() || paint.getPathEffect()) {
|
if (paint.getMaskFilter() || style.pathEffect()) {
|
||||||
// The only mask filter the native rrect drawing code could've handle was taken
|
// The only mask filter the native rrect drawing code could've handle was taken
|
||||||
// care of above.
|
// care of above.
|
||||||
// A path effect will presumably transform this rrect into something else.
|
// A path effect will presumably transform this rrect into something else.
|
||||||
@ -601,9 +600,9 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkASSERT(!strokeInfo.isDashed());
|
SkASSERT(!style.pathEffect());
|
||||||
|
|
||||||
fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
|
fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -675,10 +674,7 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrStrokeInfo strokeInfo(paint);
|
fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, GrStyle(paint));
|
||||||
SkASSERT(!strokeInfo.isDashed());
|
|
||||||
|
|
||||||
fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "SkMaskFilter.h"
|
#include "SkMaskFilter.h"
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "GrBlurUtils.h"
|
#include "GrBlurUtils.h"
|
||||||
#include "GrCaps.h"
|
#include "GrCaps.h"
|
||||||
#include "GrDrawContext.h"
|
#include "GrDrawContext.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "GrTextureParamsAdjuster.h"
|
#include "GrTextureParamsAdjuster.h"
|
||||||
#include "SkDraw.h"
|
#include "SkDraw.h"
|
||||||
#include "SkGrPriv.h"
|
#include "SkGrPriv.h"
|
||||||
@ -240,6 +240,6 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
|
|||||||
rectPath.addRect(clippedDstRect);
|
rectPath.addRect(clippedDstRect);
|
||||||
rectPath.setIsVolatile(true);
|
rectPath.setIsVolatile(true);
|
||||||
GrBlurUtils::drawPathWithMaskFilter(this->context(), fDrawContext.get(), fClip,
|
GrBlurUtils::drawPathWithMaskFilter(this->context(), fDrawContext.get(), fClip,
|
||||||
rectPath, &grPaint, viewMatrix, mf, paint.getPathEffect(),
|
rectPath, &grPaint, viewMatrix, mf, GrStyle::SimpleFill(),
|
||||||
GrStrokeInfo::FillInfo(), true);
|
true);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include "GrPathUtils.h"
|
#include "GrPathUtils.h"
|
||||||
#include "GrProcessor.h"
|
#include "GrProcessor.h"
|
||||||
#include "GrPipelineBuilder.h"
|
#include "GrPipelineBuilder.h"
|
||||||
#include "GrStrokeInfo.h"
|
|
||||||
#include "SkGeometry.h"
|
#include "SkGeometry.h"
|
||||||
#include "SkPathPriv.h"
|
#include "SkPathPriv.h"
|
||||||
#include "SkString.h"
|
#include "SkString.h"
|
||||||
@ -682,7 +681,7 @@ const GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
|
|||||||
|
|
||||||
bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
|
return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
|
||||||
args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
|
args.fStyle->isSimpleFill() && !args.fPath->isInverseFillType() &&
|
||||||
args.fPath->isConvex());
|
args.fPath->isConvex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,13 +81,14 @@ GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
|
// We don't currently apply the dash or factor it into the DF key. (skbug.com/5082)
|
||||||
|
if (args.fStyle->pathEffect()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// TODO: Support inverse fill
|
// TODO: Support inverse fill
|
||||||
if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias ||
|
if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias ||
|
||||||
SkStrokeRec::kHairline_Style == args.fStroke->getStyle() ||
|
args.fStyle->isSimpleHairline() || args.fPath->isInverseFillType() ||
|
||||||
args.fPath->isInverseFillType() || args.fPath->isVolatile() ||
|
args.fPath->isVolatile()) {
|
||||||
// We don't currently apply the dash or factor it into the DF key. (skbug.com/5082)
|
|
||||||
args.fStroke->isDashed()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,16 +101,23 @@ bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
|
|||||||
// scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP
|
// scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP
|
||||||
// the goal is to accelerate rendering of lots of small paths that may be scaling
|
// the goal is to accelerate rendering of lots of small paths that may be scaling
|
||||||
SkScalar maxScale = args.fViewMatrix->getMaxScale();
|
SkScalar maxScale = args.fViewMatrix->getMaxScale();
|
||||||
|
#if 0 // This is more accurate but changes some GMs. TODO: Standalone change to enable this.
|
||||||
|
SkRect bounds;
|
||||||
|
args.fStyle->adjustBounds(&bounds, args.fPath->getBounds());
|
||||||
|
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
|
||||||
|
#else
|
||||||
const SkRect& bounds = args.fPath->getBounds();
|
const SkRect& bounds = args.fPath->getBounds();
|
||||||
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
|
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
|
||||||
|
const SkStrokeRec& stroke = args.fStyle->strokeRec();
|
||||||
// Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit
|
// Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit
|
||||||
if (!args.fStroke->isFillStyle()) {
|
if (!stroke.isFillStyle()) {
|
||||||
SkScalar extraWidth = args.fStroke->getWidth();
|
SkScalar extraWidth = stroke.getWidth();
|
||||||
if (SkPaint::kMiter_Join == args.fStroke->getJoin()) {
|
if (SkPaint::kMiter_Join == stroke.getJoin()) {
|
||||||
extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter());
|
extraWidth = SkTMax(extraWidth, 2.0f*stroke.getMiter());
|
||||||
}
|
}
|
||||||
maxDim += extraWidth;
|
maxDim += extraWidth;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP;
|
return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP;
|
||||||
}
|
}
|
||||||
@ -552,11 +560,12 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AADistanceFieldPathBatch::Geometry geometry(*args.fStroke);
|
// It's ok to ignore style's path effect because canDrawPath filtered out path effects.
|
||||||
if (SkStrokeRec::kFill_Style == args.fStroke->getStyle()) {
|
AADistanceFieldPathBatch::Geometry geometry(args.fStyle->strokeRec());
|
||||||
|
if (args.fStyle->isSimpleFill()) {
|
||||||
geometry.fPath = *args.fPath;
|
geometry.fPath = *args.fPath;
|
||||||
} else {
|
} else {
|
||||||
args.fStroke->applyToPath(&geometry.fPath, *args.fPath);
|
args.fStyle->strokeRec().applyToPath(&geometry.fPath, *args.fPath);
|
||||||
}
|
}
|
||||||
geometry.fColor = args.fColor;
|
geometry.fColor = args.fColor;
|
||||||
geometry.fAntiAlias = args.fAntiAlias;
|
geometry.fAntiAlias = args.fAntiAlias;
|
||||||
|
@ -618,7 +618,12 @@ bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr)) {
|
if (!IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't currently handle dashing in this class though perhaps we should.
|
||||||
|
if (args.fStyle->pathEffect()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -939,11 +944,11 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const {
|
|||||||
static GrDrawBatch* create_hairline_batch(GrColor color,
|
static GrDrawBatch* create_hairline_batch(GrColor color,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& stroke,
|
const GrStyle& style,
|
||||||
const SkIRect& devClipBounds) {
|
const SkIRect& devClipBounds) {
|
||||||
SkScalar hairlineCoverage;
|
SkScalar hairlineCoverage;
|
||||||
uint8_t newCoverage = 0xff;
|
uint8_t newCoverage = 0xff;
|
||||||
if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
|
if (GrPathRenderer::IsStrokeHairlineOrEquivalent(style, viewMatrix, &hairlineCoverage)) {
|
||||||
newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
|
newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,7 +969,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
args.fPipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height(), &devClipBounds);
|
args.fPipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height(), &devClipBounds);
|
||||||
|
|
||||||
SkAutoTUnref<GrDrawBatch> batch(create_hairline_batch(args.fColor, *args.fViewMatrix, *args.fPath,
|
SkAutoTUnref<GrDrawBatch> batch(create_hairline_batch(args.fColor, *args.fViewMatrix, *args.fPath,
|
||||||
*args.fStroke, devClipBounds));
|
*args.fStyle, devClipBounds));
|
||||||
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -977,11 +982,10 @@ bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
DRAW_BATCH_TEST_DEFINE(AAHairlineBatch) {
|
DRAW_BATCH_TEST_DEFINE(AAHairlineBatch) {
|
||||||
GrColor color = GrRandomColor(random);
|
GrColor color = GrRandomColor(random);
|
||||||
SkMatrix viewMatrix = GrTest::TestMatrix(random);
|
SkMatrix viewMatrix = GrTest::TestMatrix(random);
|
||||||
GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
|
|
||||||
SkPath path = GrTest::TestPath(random);
|
SkPath path = GrTest::TestPath(random);
|
||||||
SkIRect devClipBounds;
|
SkIRect devClipBounds;
|
||||||
devClipBounds.setEmpty();
|
devClipBounds.setEmpty();
|
||||||
return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds);
|
return create_hairline_batch(color, viewMatrix, path, GrStyle::SimpleHairline(), devClipBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include "GrPathUtils.h"
|
#include "GrPathUtils.h"
|
||||||
#include "GrProcessor.h"
|
#include "GrProcessor.h"
|
||||||
#include "GrPipelineBuilder.h"
|
#include "GrPipelineBuilder.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "SkGeometry.h"
|
#include "SkGeometry.h"
|
||||||
#include "SkString.h"
|
#include "SkString.h"
|
||||||
#include "SkTraceEvent.h"
|
#include "SkTraceEvent.h"
|
||||||
@ -46,16 +46,20 @@ bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& arg
|
|||||||
if (!args.fPath->isConvex()) {
|
if (!args.fPath->isConvex()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (args.fStroke->getStyle() == SkStrokeRec::kStroke_Style) {
|
if (args.fStyle->pathEffect()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const SkStrokeRec& stroke = args.fStyle->strokeRec();
|
||||||
|
if (stroke.getStyle() == SkStrokeRec::kStroke_Style) {
|
||||||
if (!args.fViewMatrix->isSimilarity()) {
|
if (!args.fViewMatrix->isSimilarity()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * args.fStroke->getWidth();
|
SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
|
||||||
return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth && !args.fStroke->isDashed() &&
|
return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth &&
|
||||||
SkPathPriv::IsClosedSingleContour(*args.fPath) &&
|
SkPathPriv::IsClosedSingleContour(*args.fPath) &&
|
||||||
args.fStroke->getJoin() != SkPaint::Join::kRound_Join;
|
stroke.getJoin() != SkPaint::Join::kRound_Join;
|
||||||
}
|
}
|
||||||
return args.fStroke->getStyle() == SkStrokeRec::kFill_Style;
|
return stroke.getStyle() == SkStrokeRec::kFill_Style;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the result vertices and indices from the GrAAConvexTessellator
|
// extract the result vertices and indices from the GrAAConvexTessellator
|
||||||
@ -325,10 +329,10 @@ bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
geometry.fColor = args.fColor;
|
geometry.fColor = args.fColor;
|
||||||
geometry.fViewMatrix = *args.fViewMatrix;
|
geometry.fViewMatrix = *args.fViewMatrix;
|
||||||
geometry.fPath = *args.fPath;
|
geometry.fPath = *args.fPath;
|
||||||
geometry.fStrokeWidth = args.fStroke->isFillStyle() ? -1.0f : args.fStroke->getWidth();
|
bool fill = args.fStyle->isSimpleFill();
|
||||||
geometry.fJoin = args.fStroke->isFillStyle() ? SkPaint::Join::kMiter_Join :
|
geometry.fStrokeWidth = fill ? -1.0f : args.fStyle->strokeRec().getWidth();
|
||||||
args.fStroke->getJoin();
|
geometry.fJoin = fill ? SkPaint::Join::kMiter_Join : args.fStyle->strokeRec().getJoin();
|
||||||
geometry.fMiterLimit = args.fStroke->getMiter();
|
geometry.fMiterLimit = args.fStyle->strokeRec().getMiter();
|
||||||
|
|
||||||
SkAutoTUnref<GrDrawBatch> batch(AAFlatteningConvexPathBatch::Create(geometry));
|
SkAutoTUnref<GrDrawBatch> batch(AAFlatteningConvexPathBatch::Create(geometry));
|
||||||
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
SkPoint pts[2];
|
SkPoint pts[2];
|
||||||
if (args.fStroke->isDashed() && args.fPath->isLine(pts)) {
|
if (args.fStyle->isDashed() && args.fPath->isLine(pts)) {
|
||||||
return GrDashingEffect::CanDrawDashLine(pts, *args.fStroke, *args.fViewMatrix);
|
return GrDashingEffect::CanDrawDashLine(pts, *args.fStyle, *args.fViewMatrix);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
pts,
|
pts,
|
||||||
args.fAntiAlias,
|
args.fAntiAlias,
|
||||||
msaaIsEnabled,
|
msaaIsEnabled,
|
||||||
*args.fStroke));
|
*args.fStyle));
|
||||||
if (!batch) {
|
if (!batch) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -422,21 +422,20 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
|
|||||||
GrColor color,
|
GrColor color,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& origStroke,
|
const GrStyle& origStyle,
|
||||||
bool stencilOnly) {
|
bool stencilOnly) {
|
||||||
SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
|
const GrStyle* style = &origStyle;
|
||||||
|
|
||||||
SkScalar hairlineCoverage;
|
SkScalar hairlineCoverage;
|
||||||
uint8_t newCoverage = 0xff;
|
uint8_t newCoverage = 0xff;
|
||||||
if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
|
bool isHairline = false;
|
||||||
|
if (IsStrokeHairlineOrEquivalent(*style, viewMatrix, &hairlineCoverage)) {
|
||||||
newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
|
newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
|
||||||
|
style = &GrStyle::SimpleHairline();
|
||||||
if (!stroke->isHairlineStyle()) {
|
isHairline = true;
|
||||||
stroke.writable()->setHairlineStyle();
|
} else {
|
||||||
|
SkASSERT(style->isSimpleFill());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const bool isHairline = stroke->isHairlineStyle();
|
|
||||||
|
|
||||||
// Save the current xp on the draw state so we can reset it if needed
|
// Save the current xp on the draw state so we can reset it if needed
|
||||||
const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
|
const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
|
||||||
@ -460,7 +459,7 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
|
|||||||
lastPassIsBounds = false;
|
lastPassIsBounds = false;
|
||||||
drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
|
drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
|
||||||
} else {
|
} else {
|
||||||
if (single_pass_path(path, *stroke)) {
|
if (single_pass_path(path, style->strokeRec())) {
|
||||||
passCount = 1;
|
passCount = 1;
|
||||||
if (stencilOnly) {
|
if (stencilOnly) {
|
||||||
passes[0] = &gDirectToStencil;
|
passes[0] = &gDirectToStencil;
|
||||||
@ -596,9 +595,10 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
// this class can draw any path with any fill but doesn't do any anti-aliasing.
|
// this class can draw any path with any simple fill style but doesn't do any anti-aliasing.
|
||||||
return !args.fAntiAlias && (args.fStroke->isFillStyle() ||
|
return !args.fAntiAlias &&
|
||||||
IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix,
|
(args.fStyle->isSimpleFill() || IsStrokeHairlineOrEquivalent(*args.fStyle,
|
||||||
|
*args.fViewMatrix,
|
||||||
nullptr));
|
nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,7 +609,7 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
args.fColor,
|
args.fColor,
|
||||||
*args.fViewMatrix,
|
*args.fViewMatrix,
|
||||||
*args.fPath,
|
*args.fPath,
|
||||||
*args.fStroke,
|
*args.fStyle,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +618,7 @@ void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
|||||||
SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
|
SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
|
||||||
SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
|
SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
|
||||||
this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
|
this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
|
||||||
*args.fPath, GrStrokeInfo::FillInfo(), true);
|
*args.fPath, GrStyle::SimpleFill(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -631,7 +631,7 @@ DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) {
|
|||||||
|
|
||||||
// For now just hairlines because the other types of draws require two batches.
|
// For now just hairlines because the other types of draws require two batches.
|
||||||
// TODO we should figure out a way to combine the stencil and cover steps into one batch
|
// TODO we should figure out a way to combine the stencil and cover steps into one batch
|
||||||
GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
|
GrStyle style(SkStrokeRec::kHairline_InitStyle);
|
||||||
SkPath path = GrTest::TestPath(random);
|
SkPath path = GrTest::TestPath(random);
|
||||||
|
|
||||||
// Compute srcSpaceTol
|
// Compute srcSpaceTol
|
||||||
|
@ -35,7 +35,7 @@ private:
|
|||||||
GrColor,
|
GrColor,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath&,
|
const SkPath&,
|
||||||
const GrStrokeInfo&,
|
const GrStyle&,
|
||||||
bool stencilOnly);
|
bool stencilOnly);
|
||||||
|
|
||||||
bool fSeparateStencil;
|
bool fSeparateStencil;
|
||||||
|
@ -29,7 +29,7 @@ static const float kTolerance = 0.5f;
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Helpers for drawPath
|
// Helpers for drawPath
|
||||||
|
|
||||||
static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
|
static inline bool single_pass_path(const SkPath& path) {
|
||||||
if (!path.isInverseFillType()) {
|
if (!path.isInverseFillType()) {
|
||||||
return path.isConvex();
|
return path.isConvex();
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& strok
|
|||||||
|
|
||||||
GrPathRenderer::StencilSupport
|
GrPathRenderer::StencilSupport
|
||||||
GrMSAAPathRenderer::onGetStencilSupport(const SkPath& path) const {
|
GrMSAAPathRenderer::onGetStencilSupport(const SkPath& path) const {
|
||||||
if (single_pass_path(path, SkStrokeRec(SkStrokeRec::kFill_InitStyle))) {
|
if (single_pass_path(path)) {
|
||||||
return GrPathRenderer::kNoRestriction_StencilSupport;
|
return GrPathRenderer::kNoRestriction_StencilSupport;
|
||||||
} else {
|
} else {
|
||||||
return GrPathRenderer::kStencilOnly_StencilSupport;
|
return GrPathRenderer::kStencilOnly_StencilSupport;
|
||||||
@ -571,9 +571,7 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
|
|||||||
GrColor color,
|
GrColor color,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& origStroke,
|
|
||||||
bool stencilOnly) {
|
bool stencilOnly) {
|
||||||
SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
|
|
||||||
|
|
||||||
const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
|
const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
|
||||||
SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
|
SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
|
||||||
@ -586,7 +584,7 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
|
|||||||
bool reverse = false;
|
bool reverse = false;
|
||||||
bool lastPassIsBounds;
|
bool lastPassIsBounds;
|
||||||
|
|
||||||
if (single_pass_path(path, *stroke)) {
|
if (single_pass_path(path)) {
|
||||||
passCount = 1;
|
passCount = 1;
|
||||||
if (stencilOnly) {
|
if (stencilOnly) {
|
||||||
passes[0] = &gDirectToStencil;
|
passes[0] = &gDirectToStencil;
|
||||||
@ -703,34 +701,36 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) &&
|
// This path renderer does not support hairlines. We defer on anything that could be handled
|
||||||
!args.fAntiAlias;
|
// as a hairline by another path renderer. Also, arbitrary path effects could produce
|
||||||
|
// a hairline result.
|
||||||
|
return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr) &&
|
||||||
|
!args.fStyle->strokeRec().isHairlineStyle() &&
|
||||||
|
!args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrMSAAPathRenderer::onDrawPath");
|
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrMSAAPathRenderer::onDrawPath");
|
||||||
SkPath path;
|
SkPath tmpPath;
|
||||||
GrStrokeInfo stroke(*args.fStroke);
|
const SkPath* path;
|
||||||
if (stroke.isDashed()) {
|
if (args.fStyle->applies()) {
|
||||||
if (!stroke.applyDashToPath(&path, &stroke, *args.fPath)) {
|
SkStrokeRec::InitStyle fill;
|
||||||
|
SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
|
||||||
|
if (!args.fStyle->applyToPath(&tmpPath, &fill, *args.fPath, styleScale)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// We don't accept styles that are hairlines or have path effects that could produce
|
||||||
|
// hairlines.
|
||||||
|
SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
|
||||||
|
path = &tmpPath;
|
||||||
} else {
|
} else {
|
||||||
path = *args.fPath;
|
path = args.fPath;
|
||||||
}
|
|
||||||
if (!stroke.isFillStyle()) {
|
|
||||||
stroke.setResScale(SkScalarAbs(args.fViewMatrix->getMaxScale()));
|
|
||||||
if (!stroke.applyToPath(&path, path)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
stroke.setFillStyle();
|
|
||||||
}
|
}
|
||||||
return this->internalDrawPath(args.fTarget,
|
return this->internalDrawPath(args.fTarget,
|
||||||
args.fPipelineBuilder,
|
args.fPipelineBuilder,
|
||||||
args.fColor,
|
args.fColor,
|
||||||
*args.fViewMatrix,
|
*args.fViewMatrix,
|
||||||
path,
|
*path,
|
||||||
stroke,
|
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,7 +739,7 @@ void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
|||||||
SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
|
SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
|
||||||
SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
|
SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
|
||||||
this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
|
this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
|
||||||
*args.fPath, GrStrokeInfo::FillInfo(), true);
|
*args.fPath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -26,7 +26,6 @@ private:
|
|||||||
GrColor,
|
GrColor,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkPath&,
|
const SkPath&,
|
||||||
const GrStrokeInfo&,
|
|
||||||
bool stencilOnly);
|
bool stencilOnly);
|
||||||
|
|
||||||
typedef GrPathRenderer INHERITED;
|
typedef GrPathRenderer INHERITED;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "GrPathUtils.h"
|
#include "GrPathUtils.h"
|
||||||
#include "GrProcessor.h"
|
#include "GrProcessor.h"
|
||||||
#include "GrPipelineBuilder.h"
|
#include "GrPipelineBuilder.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "GrTessellator.h"
|
#include "GrTessellator.h"
|
||||||
#include "batches/GrVertexBatch.h"
|
#include "batches/GrVertexBatch.h"
|
||||||
#include "glsl/GrGLSLGeometryProcessor.h"
|
#include "glsl/GrGLSLGeometryProcessor.h"
|
||||||
@ -778,7 +778,7 @@ bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
|||||||
// We have support for even-odd rendering, but are having some troublesome
|
// We have support for even-odd rendering, but are having some troublesome
|
||||||
// seams. Disable in the presence of even-odd for now.
|
// seams. Disable in the presence of even-odd for now.
|
||||||
return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
|
return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
|
||||||
args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
|
args.fStyle->isSimpleFill() && !args.fPath->isInverseFillType() &&
|
||||||
args.fPath->getFillType() == SkPath::FillType::kWinding_FillType;
|
args.fPath->getFillType() == SkPath::FillType::kWinding_FillType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include "GrPath.h"
|
#include "GrPath.h"
|
||||||
#include "GrRenderTarget.h"
|
#include "GrRenderTarget.h"
|
||||||
#include "GrResourceProvider.h"
|
#include "GrResourceProvider.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "batches/GrRectBatchFactory.h"
|
#include "batches/GrRectBatchFactory.h"
|
||||||
|
|
||||||
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
|
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
|
||||||
@ -31,7 +31,9 @@ GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider*
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
if (args.fStroke->isHairlineStyle()) {
|
// GrPath doesn't support hairline paths. Also, an arbitrary path effect could change
|
||||||
|
// the style type to hairline.
|
||||||
|
if (!args.fStyle->hasNonDashPathEffect() || args.fStyle->strokeRec().isHairlineStyle()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!args.fIsStencilDisabled) {
|
if (!args.fIsStencilDisabled) {
|
||||||
@ -45,19 +47,19 @@ bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
|
static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
|
||||||
const GrStrokeInfo& stroke) {
|
const GrStyle& style) {
|
||||||
GrUniqueKey key;
|
GrUniqueKey key;
|
||||||
bool isVolatile;
|
bool isVolatile;
|
||||||
GrPath::ComputeKey(skPath, stroke, &key, &isVolatile);
|
GrPath::ComputeKey(skPath, style, &key, &isVolatile);
|
||||||
SkAutoTUnref<GrPath> path(
|
SkAutoTUnref<GrPath> path(
|
||||||
static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
|
static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
|
||||||
if (!path) {
|
if (!path) {
|
||||||
path.reset(resourceProvider->createPath(skPath, stroke));
|
path.reset(resourceProvider->createPath(skPath, style));
|
||||||
if (!isVolatile) {
|
if (!isVolatile) {
|
||||||
resourceProvider->assignUniqueKeyToResource(key, path);
|
resourceProvider->assignUniqueKeyToResource(key, path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SkASSERT(path->isEqualTo(skPath, stroke));
|
SkASSERT(path->isEqualTo(skPath, style));
|
||||||
}
|
}
|
||||||
return path.release();
|
return path.release();
|
||||||
}
|
}
|
||||||
@ -66,14 +68,14 @@ void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
|||||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
|
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
|
||||||
"GrStencilAndCoverPathRenderer::onStencilPath");
|
"GrStencilAndCoverPathRenderer::onStencilPath");
|
||||||
SkASSERT(!args.fPath->isInverseFillType());
|
SkASSERT(!args.fPath->isInverseFillType());
|
||||||
SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, GrStrokeInfo::FillInfo()));
|
SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, GrStyle::SimpleFill()));
|
||||||
args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
|
args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
|
GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
|
||||||
"GrStencilAndCoverPathRenderer::onDrawPath");
|
"GrStencilAndCoverPathRenderer::onDrawPath");
|
||||||
SkASSERT(!args.fStroke->isHairlineStyle());
|
SkASSERT(!args.fStyle->strokeRec().isHairlineStyle());
|
||||||
const SkPath& path = *args.fPath;
|
const SkPath& path = *args.fPath;
|
||||||
GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
|
GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
|
||||||
const SkMatrix& viewMatrix = *args.fViewMatrix;
|
const SkMatrix& viewMatrix = *args.fViewMatrix;
|
||||||
@ -85,7 +87,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
|
pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke));
|
SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStyle));
|
||||||
|
|
||||||
if (path.isInverseFillType()) {
|
if (path.isInverseFillType()) {
|
||||||
static constexpr GrStencilSettings kInvertedStencilPass(
|
static constexpr GrStencilSettings kInvertedStencilPass(
|
||||||
|
@ -105,9 +105,11 @@ GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
|
|||||||
bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
||||||
// This path renderer can draw all fill styles, all stroke styles except hairlines, but does
|
// This path renderer can draw all fill styles, all stroke styles except hairlines, but does
|
||||||
// not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to
|
// not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to
|
||||||
// simpler algorithms.
|
// simpler algorithms. Similary, we skip the non-hairlines that can be treated as hairline.
|
||||||
return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) &&
|
// An arbitrary path effect could produce a hairline result so we pass on those.
|
||||||
!args.fAntiAlias && !args.fPath->isConvex();
|
return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr) &&
|
||||||
|
!args.fStyle->strokeRec().isHairlineStyle() &&
|
||||||
|
!args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias && !args.fPath->isConvex();
|
||||||
}
|
}
|
||||||
|
|
||||||
class TessellatingPathBatch : public GrVertexBatch {
|
class TessellatingPathBatch : public GrVertexBatch {
|
||||||
@ -116,10 +118,10 @@ public:
|
|||||||
|
|
||||||
static GrDrawBatch* Create(const GrColor& color,
|
static GrDrawBatch* Create(const GrColor& color,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& stroke,
|
const GrStyle& style,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
SkRect clipBounds) {
|
SkRect clipBounds) {
|
||||||
return new TessellatingPathBatch(color, path, stroke, viewMatrix, clipBounds);
|
return new TessellatingPathBatch(color, path, style, viewMatrix, clipBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* name() const override { return "TessellatingPathBatch"; }
|
const char* name() const override { return "TessellatingPathBatch"; }
|
||||||
@ -142,48 +144,51 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void draw(Target* target, const GrGeometryProcessor* gp) const {
|
void draw(Target* target, const GrGeometryProcessor* gp) const {
|
||||||
|
GrResourceProvider* rp = target->resourceProvider();
|
||||||
|
SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
|
||||||
|
SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMatrix,
|
||||||
|
fPath.getBounds());
|
||||||
|
|
||||||
|
SkScalar styleScale = SK_Scalar1;
|
||||||
|
if (fStyle.applies()) {
|
||||||
|
styleScale = GrStyle::MatrixToScaleFactor(fViewMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
// construct a cache key from the path's genID and the view matrix
|
// construct a cache key from the path's genID and the view matrix
|
||||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||||
GrUniqueKey key;
|
GrUniqueKey key;
|
||||||
int clipBoundsSize32 =
|
int clipBoundsCnt =
|
||||||
fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0;
|
fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0;
|
||||||
int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt();
|
int styleDataCnt = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||||
GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strokeDataSize32);
|
if (styleDataCnt >= 0) {
|
||||||
|
GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsCnt + styleDataCnt);
|
||||||
builder[0] = fPath.getGenerationID();
|
builder[0] = fPath.getGenerationID();
|
||||||
builder[1] = fPath.getFillType();
|
builder[1] = fPath.getFillType();
|
||||||
// For inverse fills, the tessellation is dependent on clip bounds.
|
// For inverse fills, the tessellation is dependent on clip bounds.
|
||||||
if (fPath.isInverseFillType()) {
|
if (fPath.isInverseFillType()) {
|
||||||
memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds));
|
memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds));
|
||||||
}
|
}
|
||||||
fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]);
|
if (styleDataCnt) {
|
||||||
|
GrStyle::WriteKey(&builder[2 + clipBoundsCnt], fStyle,
|
||||||
|
GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
|
||||||
|
}
|
||||||
builder.finish();
|
builder.finish();
|
||||||
GrResourceProvider* rp = target->resourceProvider();
|
|
||||||
SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
|
SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
|
||||||
int actualCount;
|
int actualCount;
|
||||||
SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
|
|
||||||
SkScalar tol = GrPathUtils::scaleToleranceToSrc(
|
|
||||||
screenSpaceTol, fViewMatrix, fPath.getBounds());
|
|
||||||
if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
|
if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
|
||||||
this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
|
this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SkPath path;
|
SkPath path;
|
||||||
GrStrokeInfo stroke(fStroke);
|
if (fStyle.applies()) {
|
||||||
if (stroke.isDashed()) {
|
SkStrokeRec::InitStyle fill;
|
||||||
if (!stroke.applyDashToPath(&path, &stroke, fPath)) {
|
SkAssertResult(fStyle.applyToPath(&path, &fill, fPath, styleScale));
|
||||||
return;
|
SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
path = fPath;
|
path = fPath;
|
||||||
}
|
}
|
||||||
if (!stroke.isFillStyle()) {
|
|
||||||
stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale()));
|
|
||||||
if (!stroke.applyToPath(&path, path)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stroke.setFillStyle();
|
|
||||||
}
|
|
||||||
bool isLinear;
|
bool isLinear;
|
||||||
bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
|
bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
|
||||||
StaticVertexAllocator allocator(rp, canMapVB);
|
StaticVertexAllocator allocator(rp, canMapVB);
|
||||||
@ -192,7 +197,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
|
this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
|
||||||
if (!fPath.isVolatile()) {
|
if (!fPath.isVolatile() && styleDataCnt >= 0) {
|
||||||
TessInfo info;
|
TessInfo info;
|
||||||
info.fTolerance = isLinear ? 0 : tol;
|
info.fTolerance = isLinear ? 0 : tol;
|
||||||
info.fCount = count;
|
info.fCount = count;
|
||||||
@ -240,13 +245,13 @@ private:
|
|||||||
|
|
||||||
TessellatingPathBatch(const GrColor& color,
|
TessellatingPathBatch(const GrColor& color,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
const GrStrokeInfo& stroke,
|
const GrStyle& style,
|
||||||
const SkMatrix& viewMatrix,
|
const SkMatrix& viewMatrix,
|
||||||
const SkRect& clipBounds)
|
const SkRect& clipBounds)
|
||||||
: INHERITED(ClassID())
|
: INHERITED(ClassID())
|
||||||
, fColor(color)
|
, fColor(color)
|
||||||
, fPath(path)
|
, fPath(path)
|
||||||
, fStroke(stroke)
|
, fStyle(style)
|
||||||
, fViewMatrix(viewMatrix) {
|
, fViewMatrix(viewMatrix) {
|
||||||
const SkRect& pathBounds = path.getBounds();
|
const SkRect& pathBounds = path.getBounds();
|
||||||
fClipBounds = clipBounds;
|
fClipBounds = clipBounds;
|
||||||
@ -258,14 +263,13 @@ private:
|
|||||||
} else {
|
} else {
|
||||||
fBounds = path.getBounds();
|
fBounds = path.getBounds();
|
||||||
}
|
}
|
||||||
SkScalar radius = stroke.getInflationRadius();
|
style.adjustBounds(&fBounds, fBounds);
|
||||||
fBounds.outset(radius, radius);
|
|
||||||
viewMatrix.mapRect(&fBounds);
|
viewMatrix.mapRect(&fBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrColor fColor;
|
GrColor fColor;
|
||||||
SkPath fPath;
|
SkPath fPath;
|
||||||
GrStrokeInfo fStroke;
|
GrStyle fStyle;
|
||||||
SkMatrix fViewMatrix;
|
SkMatrix fViewMatrix;
|
||||||
SkRect fClipBounds; // in source space
|
SkRect fClipBounds; // in source space
|
||||||
GrXPOverridesForBatch fPipelineInfo;
|
GrXPOverridesForBatch fPipelineInfo;
|
||||||
@ -291,7 +295,7 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
|||||||
}
|
}
|
||||||
vmi.mapRect(&clipBounds);
|
vmi.mapRect(&clipBounds);
|
||||||
SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, *args.fPath,
|
SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, *args.fPath,
|
||||||
*args.fStroke, *args.fViewMatrix,
|
*args.fStyle, *args.fViewMatrix,
|
||||||
clipBounds));
|
clipBounds));
|
||||||
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
||||||
|
|
||||||
@ -313,8 +317,11 @@ DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) {
|
|||||||
SkFAIL("Cannot invert matrix\n");
|
SkFAIL("Cannot invert matrix\n");
|
||||||
}
|
}
|
||||||
vmi.mapRect(&clipBounds);
|
vmi.mapRect(&clipBounds);
|
||||||
GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random);
|
GrStyle style;
|
||||||
return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, clipBounds);
|
do {
|
||||||
|
GrTest::TestStyle(random, &style);
|
||||||
|
} while (style.strokeRec().isHairlineStyle());
|
||||||
|
return TessellatingPathBatch::Create(color, path, style, viewMatrix, clipBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include "GrDefaultGeoProcFactory.h"
|
#include "GrDefaultGeoProcFactory.h"
|
||||||
#include "GrInvariantOutput.h"
|
#include "GrInvariantOutput.h"
|
||||||
#include "GrProcessor.h"
|
#include "GrProcessor.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "SkGr.h"
|
#include "SkGr.h"
|
||||||
#include "batches/GrVertexBatch.h"
|
#include "batches/GrVertexBatch.h"
|
||||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||||
@ -29,7 +29,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Returns whether or not the gpu can fast path the dash line effect.
|
// Returns whether or not the gpu can fast path the dash line effect.
|
||||||
bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,
|
bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStyle& style,
|
||||||
const SkMatrix& viewMatrix) {
|
const SkMatrix& viewMatrix) {
|
||||||
// Pts must be either horizontal or vertical in src space
|
// Pts must be either horizontal or vertical in src space
|
||||||
if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) {
|
if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) {
|
||||||
@ -42,16 +42,16 @@ bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo&
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strokeInfo.isDashed() || 2 != strokeInfo.getDashCount()) {
|
if (!style.isDashed() || 2 != style.dashIntervalCnt()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkScalar* intervals = strokeInfo.getDashIntervals();
|
const SkScalar* intervals = style.dashIntervals();
|
||||||
if (0 == intervals[0] && 0 == intervals[1]) {
|
if (0 == intervals[0] && 0 == intervals[1]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPaint::Cap cap = strokeInfo.getCap();
|
SkPaint::Cap cap = style.strokeRec().getCap();
|
||||||
// Current we do don't handle Round or Square cap dashes
|
// Current we do don't handle Round or Square cap dashes
|
||||||
if (SkPaint::kRound_Cap == cap && intervals[0] != 0.f) {
|
if (SkPaint::kRound_Cap == cap && intervals[0] != 0.f) {
|
||||||
return false;
|
return false;
|
||||||
@ -690,14 +690,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static GrDrawBatch* create_batch(GrColor color, const SkMatrix& viewMatrix, const SkPoint pts[2],
|
static GrDrawBatch* create_batch(GrColor color, const SkMatrix& viewMatrix, const SkPoint pts[2],
|
||||||
bool useAA, const GrStrokeInfo& strokeInfo, bool msaaRT) {
|
bool useAA, const GrStyle& style, bool msaaRT) {
|
||||||
const SkScalar* intervals = strokeInfo.getDashIntervals();
|
SkASSERT(GrDashingEffect::CanDrawDashLine(pts, style, viewMatrix));
|
||||||
SkScalar phase = strokeInfo.getDashPhase();
|
const SkScalar* intervals = style.dashIntervals();
|
||||||
|
SkScalar phase = style.dashPhase();
|
||||||
|
|
||||||
SkPaint::Cap cap = strokeInfo.getCap();
|
SkPaint::Cap cap = style.strokeRec().getCap();
|
||||||
|
|
||||||
DashBatch::Geometry geometry;
|
DashBatch::Geometry geometry;
|
||||||
geometry.fSrcStrokeWidth = strokeInfo.getWidth();
|
geometry.fSrcStrokeWidth = style.strokeRec().getWidth();
|
||||||
|
|
||||||
// the phase should be normalized to be [0, sum of all intervals)
|
// the phase should be normalized to be [0, sum of all intervals)
|
||||||
SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]);
|
SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]);
|
||||||
@ -747,8 +748,8 @@ GrDrawBatch* GrDashingEffect::CreateDashLineBatch(GrColor color,
|
|||||||
const SkPoint pts[2],
|
const SkPoint pts[2],
|
||||||
bool useAA,
|
bool useAA,
|
||||||
bool msaaIsEnabled,
|
bool msaaIsEnabled,
|
||||||
const GrStrokeInfo& strokeInfo) {
|
const GrStyle& style) {
|
||||||
return create_batch(color, viewMatrix, pts, useAA, strokeInfo, msaaIsEnabled);
|
return create_batch(color, viewMatrix, pts, useAA, style, msaaIsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1289,17 +1290,11 @@ DRAW_BATCH_TEST_DEFINE(DashBatch) {
|
|||||||
p.setStyle(SkPaint::kStroke_Style);
|
p.setStyle(SkPaint::kStroke_Style);
|
||||||
p.setStrokeWidth(SkIntToScalar(1));
|
p.setStrokeWidth(SkIntToScalar(1));
|
||||||
p.setStrokeCap(cap);
|
p.setStrokeCap(cap);
|
||||||
|
p.setPathEffect(GrTest::TestDashPathEffect::Make(intervals, 2, phase));
|
||||||
|
|
||||||
GrStrokeInfo strokeInfo(p);
|
GrStyle style(p);
|
||||||
|
|
||||||
SkPathEffect::DashInfo info;
|
return create_batch(color, viewMatrix, pts, useAA, style, msaaRT);
|
||||||
info.fIntervals = intervals;
|
|
||||||
info.fCount = 2;
|
|
||||||
info.fPhase = phase;
|
|
||||||
SkDEBUGCODE(bool success = ) strokeInfo.setDashInfo(info);
|
|
||||||
SkASSERT(success);
|
|
||||||
|
|
||||||
return create_batch(color, viewMatrix, pts, useAA, strokeInfo, msaaRT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
class GrClip;
|
class GrClip;
|
||||||
class GrDrawBatch;
|
class GrDrawBatch;
|
||||||
class GrStrokeInfo;
|
class GrStyle;
|
||||||
|
|
||||||
namespace GrDashingEffect {
|
namespace GrDashingEffect {
|
||||||
GrDrawBatch* CreateDashLineBatch(GrColor,
|
GrDrawBatch* CreateDashLineBatch(GrColor,
|
||||||
@ -22,8 +22,8 @@ namespace GrDashingEffect {
|
|||||||
const SkPoint pts[2],
|
const SkPoint pts[2],
|
||||||
bool useAA,
|
bool useAA,
|
||||||
bool msaaIsEnabled,
|
bool msaaIsEnabled,
|
||||||
const GrStrokeInfo& strokeInfo);
|
const GrStyle& style);
|
||||||
bool CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,
|
bool CanDrawDashLine(const SkPoint pts[2], const GrStyle& style,
|
||||||
const SkMatrix& viewMatrix);
|
const SkMatrix& viewMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "GrGLPath.h"
|
#include "GrGLPath.h"
|
||||||
#include "GrGLPathRendering.h"
|
#include "GrGLPathRendering.h"
|
||||||
#include "GrGLGpu.h"
|
#include "GrGLGpu.h"
|
||||||
|
#include "GrStyle.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
|
inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
|
||||||
@ -251,9 +252,7 @@ void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
|
|||||||
SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
|
SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke) {
|
void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) {
|
||||||
SkASSERT(stroke.needToApply());
|
|
||||||
SkASSERT(!stroke.isDashed());
|
|
||||||
SkASSERT(!stroke.isHairlineStyle());
|
SkASSERT(!stroke.isHairlineStyle());
|
||||||
GR_GL_CALL(gpu->glInterface(),
|
GR_GL_CALL(gpu->glInterface(),
|
||||||
PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
|
PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
|
||||||
@ -270,8 +269,8 @@ void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
|
|||||||
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
|
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& origStroke)
|
GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style)
|
||||||
: INHERITED(gpu, origSkPath, origStroke),
|
: INHERITED(gpu, origSkPath, style),
|
||||||
fPathID(gpu->glPathRendering()->genPaths(1)) {
|
fPathID(gpu->glPathRendering()->genPaths(1)) {
|
||||||
|
|
||||||
if (origSkPath.isEmpty()) {
|
if (origSkPath.isEmpty()) {
|
||||||
@ -281,21 +280,21 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o
|
|||||||
} else {
|
} else {
|
||||||
const SkPath* skPath = &origSkPath;
|
const SkPath* skPath = &origSkPath;
|
||||||
SkTLazy<SkPath> tmpPath;
|
SkTLazy<SkPath> tmpPath;
|
||||||
const GrStrokeInfo* stroke = &origStroke;
|
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
||||||
GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
|
|
||||||
|
|
||||||
if (stroke->isDashed()) {
|
if (style.pathEffect()) {
|
||||||
// Skia stroking and NVPR stroking differ with respect to dashing
|
// Skia stroking and NVPR stroking differ with respect to dashing
|
||||||
// pattern.
|
// pattern.
|
||||||
// Convert a dashing to either a stroke or a fill.
|
// Convert a dashing (or other path effect) to either a stroke or a fill.
|
||||||
if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
|
if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) {
|
||||||
skPath = tmpPath.get();
|
skPath = tmpPath.get();
|
||||||
stroke = &tmpStroke;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
stroke = style.strokeRec();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool didInit = false;
|
bool didInit = false;
|
||||||
if (stroke->needToApply() && stroke->getCap() != SkPaint::kButt_Cap) {
|
if (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap) {
|
||||||
// Skia stroking and NVPR stroking differ with respect to stroking
|
// Skia stroking and NVPR stroking differ with respect to stroking
|
||||||
// end caps of empty subpaths.
|
// end caps of empty subpaths.
|
||||||
// Convert stroke to fill if path contains empty subpaths.
|
// Convert stroke to fill if path contains empty subpaths.
|
||||||
@ -304,10 +303,9 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o
|
|||||||
if (!tmpPath.isValid()) {
|
if (!tmpPath.isValid()) {
|
||||||
tmpPath.init();
|
tmpPath.init();
|
||||||
}
|
}
|
||||||
SkAssertResult(stroke->applyToPath(tmpPath.get(), *skPath));
|
SkAssertResult(stroke.applyToPath(tmpPath.get(), *skPath));
|
||||||
skPath = tmpPath.get();
|
skPath = tmpPath.get();
|
||||||
tmpStroke.setFillStyle();
|
stroke.setFillStyle();
|
||||||
stroke = &tmpStroke;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,18 +313,16 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o
|
|||||||
InitPathObjectPathData(gpu, fPathID, *skPath);
|
InitPathObjectPathData(gpu, fPathID, *skPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
fShouldStroke = stroke->needToApply();
|
fShouldStroke = stroke.needToApply();
|
||||||
fShouldFill = stroke->isFillStyle() ||
|
fShouldFill = stroke.isFillStyle() ||
|
||||||
stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style;
|
stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
|
||||||
|
|
||||||
fFillType = convert_skpath_filltype(skPath->getFillType());
|
fFillType = convert_skpath_filltype(skPath->getFillType());
|
||||||
fBounds = skPath->getBounds();
|
fBounds = skPath->getBounds();
|
||||||
|
SkScalar radius = stroke.getInflationRadius();
|
||||||
|
fBounds.outset(radius, radius);
|
||||||
if (fShouldStroke) {
|
if (fShouldStroke) {
|
||||||
InitPathObjectStroke(gpu, fPathID, *stroke);
|
InitPathObjectStroke(gpu, fPathID, stroke);
|
||||||
|
|
||||||
// FIXME: try to account for stroking, without rasterizing the stroke.
|
|
||||||
fBounds.outset(stroke->getWidth(), stroke->getWidth());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "gl/GrGLTypes.h"
|
#include "gl/GrGLTypes.h"
|
||||||
|
|
||||||
class GrGLGpu;
|
class GrGLGpu;
|
||||||
|
class GrStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently this represents a path built using GL_NV_path_rendering. If we
|
* Currently this represents a path built using GL_NV_path_rendering. If we
|
||||||
@ -27,12 +28,12 @@ public:
|
|||||||
static void InitPathObjectPathData(GrGLGpu*,
|
static void InitPathObjectPathData(GrGLGpu*,
|
||||||
GrGLuint pathID,
|
GrGLuint pathID,
|
||||||
const SkPath&);
|
const SkPath&);
|
||||||
static void InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke);
|
static void InitPathObjectStroke(GrGLGpu*, GrGLuint pathID, const SkStrokeRec&);
|
||||||
|
|
||||||
static void InitPathObjectEmptyPath(GrGLGpu*, GrGLuint pathID);
|
static void InitPathObjectEmptyPath(GrGLGpu*, GrGLuint pathID);
|
||||||
|
|
||||||
|
|
||||||
GrGLPath(GrGLGpu* gpu, const SkPath& path, const GrStrokeInfo& stroke);
|
GrGLPath(GrGLGpu*, const SkPath&, const GrStyle&);
|
||||||
GrGLuint pathID() const { return fPathID; }
|
GrGLuint pathID() const { return fPathID; }
|
||||||
|
|
||||||
bool shouldStroke() const { return fShouldStroke; }
|
bool shouldStroke() const { return fShouldStroke; }
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
#include "GrGLPathRendering.h"
|
#include "GrGLPathRendering.h"
|
||||||
#include "GrGLGpu.h"
|
#include "GrGLGpu.h"
|
||||||
|
|
||||||
GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStrokeInfo& stroke)
|
GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStyle& style)
|
||||||
: INHERITED(gpu, pathGenerator),
|
: INHERITED(gpu, pathGenerator),
|
||||||
fStroke(stroke),
|
fStyle(style),
|
||||||
fBasePathID(gpu->glPathRendering()->genPaths(this->getNumPaths())),
|
fBasePathID(gpu->glPathRendering()->genPaths(this->getNumPaths())),
|
||||||
fGpuMemorySize(0) {
|
fGpuMemorySize(0) {
|
||||||
this->init();
|
this->init();
|
||||||
@ -23,9 +23,9 @@ GrGLPathRange::GrGLPathRange(GrGLGpu* gpu,
|
|||||||
GrGLuint basePathID,
|
GrGLuint basePathID,
|
||||||
int numPaths,
|
int numPaths,
|
||||||
size_t gpuMemorySize,
|
size_t gpuMemorySize,
|
||||||
const GrStrokeInfo& stroke)
|
const GrStyle& style)
|
||||||
: INHERITED(gpu, numPaths),
|
: INHERITED(gpu, numPaths),
|
||||||
fStroke(stroke),
|
fStyle(style),
|
||||||
fBasePathID(basePathID),
|
fBasePathID(basePathID),
|
||||||
fGpuMemorySize(gpuMemorySize) {
|
fGpuMemorySize(gpuMemorySize) {
|
||||||
this->init();
|
this->init();
|
||||||
@ -33,19 +33,20 @@ GrGLPathRange::GrGLPathRange(GrGLGpu* gpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrGLPathRange::init() {
|
void GrGLPathRange::init() {
|
||||||
|
const SkStrokeRec& stroke = fStyle.strokeRec();
|
||||||
// Must force fill:
|
// Must force fill:
|
||||||
// * dashing: NVPR stroke dashing is different to Skia.
|
// * dashing: NVPR stroke dashing is different to Skia.
|
||||||
// * end caps: NVPR stroking degenerate contours with end caps is different to Skia.
|
// * end caps: NVPR stroking degenerate contours with end caps is different to Skia.
|
||||||
bool forceFill = fStroke.isDashed() ||
|
bool forceFill = fStyle.pathEffect() ||
|
||||||
(fStroke.needToApply() && fStroke.getCap() != SkPaint::kButt_Cap);
|
(stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap);
|
||||||
|
|
||||||
if (forceFill) {
|
if (forceFill) {
|
||||||
fShouldStroke = false;
|
fShouldStroke = false;
|
||||||
fShouldFill = true;
|
fShouldFill = true;
|
||||||
} else {
|
} else {
|
||||||
fShouldStroke = fStroke.needToApply();
|
fShouldStroke = stroke.needToApply();
|
||||||
fShouldFill = fStroke.isFillStyle() ||
|
fShouldFill = stroke.isFillStyle() ||
|
||||||
fStroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
|
stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +55,6 @@ void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const {
|
|||||||
if (nullptr == gpu) {
|
if (nullptr == gpu) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the path at this index hasn't been initted already.
|
// Make sure the path at this index hasn't been initted already.
|
||||||
SkDEBUGCODE(
|
SkDEBUGCODE(
|
||||||
GrGLboolean isPath;
|
GrGLboolean isPath;
|
||||||
@ -65,32 +65,25 @@ void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const {
|
|||||||
GrGLPath::InitPathObjectEmptyPath(gpu, fBasePathID + index);
|
GrGLPath::InitPathObjectEmptyPath(gpu, fBasePathID + index);
|
||||||
} else if (fShouldStroke) {
|
} else if (fShouldStroke) {
|
||||||
GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, origSkPath);
|
GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, origSkPath);
|
||||||
GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStroke);
|
GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStyle.strokeRec());
|
||||||
} else {
|
} else {
|
||||||
const SkPath* skPath = &origSkPath;
|
const SkPath* skPath = &origSkPath;
|
||||||
SkTLazy<SkPath> tmpPath;
|
SkTLazy<SkPath> tmpPath;
|
||||||
const GrStrokeInfo* stroke = &fStroke;
|
if (!fStyle.isSimpleFill()) {
|
||||||
GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
|
SkStrokeRec::InitStyle fill;
|
||||||
|
// The path effect must be applied to the path. However, if a path effect is present,
|
||||||
// Dashing must be applied to the path. However, if dashing is present,
|
// we must convert all the paths to fills. The path effect application may leave
|
||||||
// we must convert all the paths to fills. The GrStrokeInfo::applyDash leaves
|
|
||||||
// simple paths as strokes but converts other paths to fills.
|
// simple paths as strokes but converts other paths to fills.
|
||||||
// Thus we must stroke the strokes here, so that all paths in the
|
// Thus we must stroke the strokes here, so that all paths in the
|
||||||
// path range are using the same style.
|
// path range are using the same style.
|
||||||
if (fStroke.isDashed()) {
|
if (!fStyle.applyToPath(tmpPath.init(), &fill, *skPath, SK_Scalar1)) {
|
||||||
if (!stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// We shouldn't have allowed hairlines or arbitrary path effect styles to get here
|
||||||
|
// so after application we better have a filled path.
|
||||||
|
SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
|
||||||
skPath = tmpPath.get();
|
skPath = tmpPath.get();
|
||||||
stroke = &tmpStroke;
|
|
||||||
}
|
|
||||||
if (stroke->needToApply()) {
|
|
||||||
if (!tmpPath.isValid()) {
|
|
||||||
tmpPath.init();
|
|
||||||
}
|
|
||||||
if (!stroke->applyToPath(tmpPath.get(), *tmpPath.get())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, *skPath);
|
GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, *skPath);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#define GrGLPathRange_DEFINED
|
#define GrGLPathRange_DEFINED
|
||||||
|
|
||||||
#include "../GrPathRange.h"
|
#include "../GrPathRange.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "gl/GrGLTypes.h"
|
#include "gl/GrGLTypes.h"
|
||||||
|
|
||||||
class GrGLGpu;
|
class GrGLGpu;
|
||||||
@ -26,7 +26,7 @@ public:
|
|||||||
* Initialize a GL path range from a PathGenerator. This class will allocate
|
* Initialize a GL path range from a PathGenerator. This class will allocate
|
||||||
* the GPU path objects and initialize them lazily.
|
* the GPU path objects and initialize them lazily.
|
||||||
*/
|
*/
|
||||||
GrGLPathRange(GrGLGpu*, PathGenerator*, const GrStrokeInfo&);
|
GrGLPathRange(GrGLGpu*, PathGenerator*, const GrStyle&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a GL path range from an existing range of pre-initialized GPU
|
* Initialize a GL path range from an existing range of pre-initialized GPU
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
GrGLuint basePathID,
|
GrGLuint basePathID,
|
||||||
int numPaths,
|
int numPaths,
|
||||||
size_t gpuMemorySize,
|
size_t gpuMemorySize,
|
||||||
const GrStrokeInfo&);
|
const GrStyle&);
|
||||||
|
|
||||||
GrGLuint basePathID() const { return fBasePathID; }
|
GrGLuint basePathID() const { return fBasePathID; }
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ private:
|
|||||||
void init();
|
void init();
|
||||||
size_t onGpuMemorySize() const override { return fGpuMemorySize; }
|
size_t onGpuMemorySize() const override { return fGpuMemorySize; }
|
||||||
|
|
||||||
const GrStrokeInfo fStroke;
|
const GrStyle fStyle;
|
||||||
GrGLuint fBasePathID;
|
GrGLuint fBasePathID;
|
||||||
mutable size_t fGpuMemorySize;
|
mutable size_t fGpuMemorySize;
|
||||||
bool fShouldStroke;
|
bool fShouldStroke;
|
||||||
|
@ -106,13 +106,13 @@ void GrGLPathRendering::resetContext() {
|
|||||||
fHWPathStencilSettings.invalidate();
|
fHWPathStencilSettings.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
|
GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
|
||||||
return new GrGLPath(this->gpu(), inPath, stroke);
|
return new GrGLPath(this->gpu(), inPath, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
|
GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
|
||||||
const GrStrokeInfo& stroke) {
|
const GrStyle& style) {
|
||||||
return new GrGLPathRange(this->gpu(), pathGenerator, stroke);
|
return new GrGLPathRange(this->gpu(), pathGenerator, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
|
void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
class GrGLNameAllocator;
|
class GrGLNameAllocator;
|
||||||
class GrGLGpu;
|
class GrGLGpu;
|
||||||
|
class GrStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class wraps the NV_path_rendering extension and manages its various
|
* This class wraps the NV_path_rendering extension and manages its various
|
||||||
@ -33,9 +34,9 @@ public:
|
|||||||
virtual ~GrGLPathRendering();
|
virtual ~GrGLPathRendering();
|
||||||
|
|
||||||
// GrPathRendering implementations.
|
// GrPathRendering implementations.
|
||||||
GrPath* createPath(const SkPath&, const GrStrokeInfo&) override;
|
GrPath* createPath(const SkPath&, const GrStyle&) override;
|
||||||
virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*,
|
virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*,
|
||||||
const GrStrokeInfo&) override;
|
const GrStyle&) override;
|
||||||
|
|
||||||
/* Called when the 3D context state is unknown. */
|
/* Called when the 3D context state is unknown. */
|
||||||
void resetContext();
|
void resetContext();
|
||||||
|
@ -235,6 +235,18 @@ void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int style_key_cnt(const GrStyle& style) {
|
||||||
|
int cnt = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||||
|
// We should be able to make a key because we filtered out arbitrary path effects.
|
||||||
|
SkASSERT(cnt > 0);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write_style_key(uint32_t* dst, const GrStyle& style) {
|
||||||
|
// Pass 1 for the scale since the GPU will apply the style not GrStyle::applyToPath().
|
||||||
|
GrStyle::WriteKey(dst, style, GrStyle::Apply::kPathEffectAndStrokeRec, SK_Scalar1);
|
||||||
|
}
|
||||||
|
|
||||||
const GrStencilAndCoverTextContext::TextBlob&
|
const GrStencilAndCoverTextContext::TextBlob&
|
||||||
GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
|
GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
|
||||||
const SkPaint& skPaint) {
|
const SkPaint& skPaint) {
|
||||||
@ -253,11 +265,11 @@ GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
|
|||||||
fCacheSize += blob->cpuMemorySize();
|
fCacheSize += blob->cpuMemorySize();
|
||||||
return *blob;
|
return *blob;
|
||||||
} else {
|
} else {
|
||||||
GrStrokeInfo stroke(skPaint);
|
GrStyle style(skPaint);
|
||||||
SkSTArray<4, uint32_t, true> key;
|
SkSTArray<4, uint32_t, true> key;
|
||||||
key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt());
|
key.reset(1 + style_key_cnt(style));
|
||||||
key[0] = skBlob->uniqueID();
|
key[0] = skBlob->uniqueID();
|
||||||
stroke.asUniqueKeyFragment(&key[1]);
|
write_style_key(&key[1], style);
|
||||||
if (TextBlob** found = fBlobKeyCache.find(key)) {
|
if (TextBlob** found = fBlobKeyCache.find(key)) {
|
||||||
fLRUList.remove(*found);
|
fLRUList.remove(*found);
|
||||||
fLRUList.addToTail(*found);
|
fLRUList.addToTail(*found);
|
||||||
@ -353,41 +365,48 @@ private:
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
|
GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
|
||||||
: fStroke(fontAndStroke),
|
: fStyle(fontAndStroke),
|
||||||
fFont(fontAndStroke),
|
fFont(fontAndStroke),
|
||||||
fTotalGlyphCount(0),
|
fTotalGlyphCount(0),
|
||||||
fFallbackGlyphCount(0),
|
fFallbackGlyphCount(0),
|
||||||
fDetachedGlyphCache(nullptr),
|
fDetachedGlyphCache(nullptr),
|
||||||
fLastDrawnGlyphsID(SK_InvalidUniqueID) {
|
fLastDrawnGlyphsID(SK_InvalidUniqueID) {
|
||||||
SkASSERT(fFont.getTextSize() > 0);
|
SkASSERT(fFont.getTextSize() > 0);
|
||||||
SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
|
SkASSERT(!fStyle.hasNonDashPathEffect()); // Arbitrary path effects not supported.
|
||||||
|
SkASSERT(!fStyle.isSimpleHairline()); // Hairlines are not supported.
|
||||||
|
|
||||||
// Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path
|
// Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path
|
||||||
// rendering API for stroking).
|
// rendering API for stroking).
|
||||||
fFont.setStyle(SkPaint::kFill_Style);
|
fFont.setStyle(SkPaint::kFill_Style);
|
||||||
|
|
||||||
if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
|
if (fFont.isFakeBoldText() && fStyle.isSimpleFill()) {
|
||||||
|
const SkStrokeRec& stroke = fStyle.strokeRec();
|
||||||
// Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke.
|
// Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke.
|
||||||
SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(),
|
SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(),
|
||||||
kStdFakeBoldInterpKeys,
|
kStdFakeBoldInterpKeys,
|
||||||
kStdFakeBoldInterpValues,
|
kStdFakeBoldInterpValues,
|
||||||
kStdFakeBoldInterpLength);
|
kStdFakeBoldInterpLength);
|
||||||
SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale);
|
SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale);
|
||||||
fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
|
|
||||||
true /*strokeAndFill*/);
|
|
||||||
|
|
||||||
|
SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle);
|
||||||
|
strokeRec.setStrokeStyle(stroke.needToApply() ? stroke.getWidth() + extra : extra,
|
||||||
|
true /*strokeAndFill*/);
|
||||||
|
fStyle = GrStyle(strokeRec, fStyle.pathEffect());
|
||||||
fFont.setFakeBoldText(false);
|
fFont.setFakeBoldText(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fFont.getPathEffect() && !fStroke.isDashed()) {
|
if (!fFont.getPathEffect() && !fStyle.isDashed()) {
|
||||||
|
const SkStrokeRec& stroke = fStyle.strokeRec();
|
||||||
// We can draw the glyphs from canonically sized paths.
|
// We can draw the glyphs from canonically sized paths.
|
||||||
fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
|
fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
|
||||||
fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextSize();
|
fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextSize();
|
||||||
|
|
||||||
// Compensate for the glyphs being scaled by fTextRatio.
|
// Compensate for the glyphs being scaled by fTextRatio.
|
||||||
if (!fStroke.isFillStyle()) {
|
if (!fStyle.isSimpleFill()) {
|
||||||
fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
|
SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle);
|
||||||
SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
|
strokeRec.setStrokeStyle(stroke.getWidth() / fTextRatio,
|
||||||
|
SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle());
|
||||||
|
fStyle = GrStyle(strokeRec, fStyle.pathEffect());
|
||||||
}
|
}
|
||||||
|
|
||||||
fFont.setLinearText(true);
|
fFont.setLinearText(true);
|
||||||
@ -407,7 +426,7 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate the key that will be used to cache the GPU glyph path objects.
|
// Generate the key that will be used to cache the GPU glyph path objects.
|
||||||
if (fUsingRawGlyphPaths && fStroke.isFillStyle()) {
|
if (fUsingRawGlyphPaths && fStyle.isSimpleFill()) {
|
||||||
static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain();
|
||||||
|
|
||||||
const SkTypeface* typeface = fFont.getTypeface();
|
const SkTypeface* typeface = fFont.getTypeface();
|
||||||
@ -416,24 +435,30 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
|
|||||||
} else {
|
} else {
|
||||||
static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
|
static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
|
||||||
|
|
||||||
int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt();
|
int styleDataCount = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
|
||||||
|
// Key should be valid since we opted out of drawing arbitrary path effects.
|
||||||
|
SkASSERT(styleDataCount >= 0);
|
||||||
if (fUsingRawGlyphPaths) {
|
if (fUsingRawGlyphPaths) {
|
||||||
const SkTypeface* typeface = fFont.getTypeface();
|
const SkTypeface* typeface = fFont.getTypeface();
|
||||||
GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + strokeDataCount);
|
GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + styleDataCount);
|
||||||
reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
|
reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
|
||||||
reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount;
|
reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount;
|
||||||
fStroke.asUniqueKeyFragment(&builder[2]);
|
if (styleDataCount) {
|
||||||
|
write_style_key(&builder[2], fStyle);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SkGlyphCache* glyphCache = this->getGlyphCache();
|
SkGlyphCache* glyphCache = this->getGlyphCache();
|
||||||
const SkTypeface* typeface = glyphCache->getScalerContext()->getTypeface();
|
const SkTypeface* typeface = glyphCache->getScalerContext()->getTypeface();
|
||||||
const SkDescriptor* desc = &glyphCache->getDescriptor();
|
const SkDescriptor* desc = &glyphCache->getDescriptor();
|
||||||
int descDataCount = (desc->getLength() + 3) / 4;
|
int descDataCount = (desc->getLength() + 3) / 4;
|
||||||
GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain,
|
GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain,
|
||||||
2 + strokeDataCount + descDataCount);
|
2 + styleDataCount + descDataCount);
|
||||||
reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
|
reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
|
||||||
reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount | (descDataCount << 16);
|
reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount | (descDataCount << 16);
|
||||||
fStroke.asUniqueKeyFragment(&builder[2]);
|
if (styleDataCount) {
|
||||||
memcpy(&builder[2 + strokeDataCount], desc, desc->getLength());
|
write_style_key(&builder[2], fStyle);
|
||||||
|
}
|
||||||
|
memcpy(&builder[2 + styleDataCount], desc, desc->getLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,13 +566,13 @@ GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx)
|
|||||||
if (fUsingRawGlyphPaths) {
|
if (fUsingRawGlyphPaths) {
|
||||||
SkScalerContextEffects noeffects;
|
SkScalerContextEffects noeffects;
|
||||||
glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), noeffects,
|
glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), noeffects,
|
||||||
nullptr, fStroke);
|
nullptr, fStyle);
|
||||||
} else {
|
} else {
|
||||||
SkGlyphCache* cache = this->getGlyphCache();
|
SkGlyphCache* cache = this->getGlyphCache();
|
||||||
glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(),
|
glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(),
|
||||||
cache->getScalerContext()->getEffects(),
|
cache->getScalerContext()->getEffects(),
|
||||||
&cache->getDescriptor(),
|
&cache->getDescriptor(),
|
||||||
fStroke);
|
fStyle);
|
||||||
}
|
}
|
||||||
ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs);
|
ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs);
|
||||||
}
|
}
|
||||||
@ -621,9 +646,9 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
|
|||||||
|
|
||||||
if (fFallbackTextBlob) {
|
if (fFallbackTextBlob) {
|
||||||
SkPaint fallbackSkPaint(originalSkPaint);
|
SkPaint fallbackSkPaint(originalSkPaint);
|
||||||
fStroke.applyToPaint(&fallbackSkPaint);
|
fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
|
||||||
if (!fStroke.isFillStyle()) {
|
if (!fStyle.isSimpleFill()) {
|
||||||
fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
|
fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fallbackSkPaint,
|
fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fallbackSkPaint,
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#define GrStencilAndCoverTextContext_DEFINED
|
#define GrStencilAndCoverTextContext_DEFINED
|
||||||
|
|
||||||
#include "GrDrawContext.h"
|
#include "GrDrawContext.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "SkDrawFilter.h"
|
#include "SkDrawFilter.h"
|
||||||
#include "SkTextBlob.h"
|
#include "SkTextBlob.h"
|
||||||
#include "SkTHash.h"
|
#include "SkTHash.h"
|
||||||
@ -94,7 +94,7 @@ private:
|
|||||||
GrPathRange* createGlyphs(GrContext*) const;
|
GrPathRange* createGlyphs(GrContext*) const;
|
||||||
void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*);
|
void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*);
|
||||||
|
|
||||||
GrStrokeInfo fStroke;
|
GrStyle fStyle;
|
||||||
SkPaint fFont;
|
SkPaint fFont;
|
||||||
SkScalar fTextRatio;
|
SkScalar fTextRatio;
|
||||||
float fTextInverseRatio;
|
float fTextInverseRatio;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include "GrContext.h"
|
#include "GrContext.h"
|
||||||
#include "GrPath.h"
|
#include "GrPath.h"
|
||||||
#include "GrStrokeInfo.h"
|
#include "GrStyle.h"
|
||||||
#include "SkBitmap.h"
|
#include "SkBitmap.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
#include "SkColor.h"
|
#include "SkColor.h"
|
||||||
@ -104,9 +104,8 @@ DEF_GPUTEST(GrPathKeys, reporter, /*factory*/) {
|
|||||||
|
|
||||||
bool isVolatile;
|
bool isVolatile;
|
||||||
GrUniqueKey key1, key2;
|
GrUniqueKey key1, key2;
|
||||||
GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
|
GrPath::ComputeKey(path1, GrStyle::SimpleFill(), &key1, &isVolatile);
|
||||||
GrPath::ComputeKey(path1, stroke, &key1, &isVolatile);
|
GrPath::ComputeKey(path2, GrStyle::SimpleFill(), &key2, &isVolatile);
|
||||||
GrPath::ComputeKey(path2, stroke, &key2, &isVolatile);
|
|
||||||
REPORTER_ASSERT(reporter, key1 != key2);
|
REPORTER_ASSERT(reporter, key1 != key2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, GrResourceProvider*
|
|||||||
pipelineBuilder.setXPFactory(
|
pipelineBuilder.setXPFactory(
|
||||||
GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
|
GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
|
||||||
pipelineBuilder.setRenderTarget(rt);
|
pipelineBuilder.setRenderTarget(rt);
|
||||||
GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
|
GrStyle style(SkStrokeRec::kFill_InitStyle);
|
||||||
GrPathRenderer::DrawPathArgs args;
|
GrPathRenderer::DrawPathArgs args;
|
||||||
args.fTarget = dt;
|
args.fTarget = dt;
|
||||||
args.fPipelineBuilder = &pipelineBuilder;
|
args.fPipelineBuilder = &pipelineBuilder;
|
||||||
@ -247,7 +247,7 @@ static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, GrResourceProvider*
|
|||||||
args.fColor = GrColor_WHITE;
|
args.fColor = GrColor_WHITE;
|
||||||
args.fViewMatrix = &SkMatrix::I();
|
args.fViewMatrix = &SkMatrix::I();
|
||||||
args.fPath = &path;
|
args.fPath = &path;
|
||||||
args.fStroke = &stroke;
|
args.fStyle = &style;
|
||||||
args.fAntiAlias = false;
|
args.fAntiAlias = false;
|
||||||
tess.drawPath(args);
|
tess.drawPath(args);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user