зеркало из https://github.com/mozilla/moz-skia.git
Added dashing fast path
https://codereview.appspot.com/6844067/ git-svn-id: http://skia.googlecode.com/svn/trunk@6585 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
edb26fdb83
Коммит
629ab54066
|
@ -171,9 +171,87 @@ protected:
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Test out the on/off line dashing Chrome if fond of
|
||||||
|
class Dashing3GM : public skiagm::GM {
|
||||||
|
public:
|
||||||
|
Dashing3GM() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SkString onShortName() {
|
||||||
|
return SkString("dashing3");
|
||||||
|
}
|
||||||
|
|
||||||
|
SkISize onISize() { return skiagm::make_isize(640, 480); }
|
||||||
|
|
||||||
|
// Draw a 100x100 block of dashed lines. The horizontal ones are BW
|
||||||
|
// while the vertical ones are AA.
|
||||||
|
void drawDashedLines(SkCanvas* canvas, SkScalar length, SkScalar phase) {
|
||||||
|
SkPaint p;
|
||||||
|
p.setColor(SK_ColorBLACK);
|
||||||
|
p.setStyle(SkPaint::kStroke_Style);
|
||||||
|
p.setStrokeWidth(SK_Scalar1);
|
||||||
|
|
||||||
|
SkScalar intervals[2] = { SK_Scalar1, SK_Scalar1 };
|
||||||
|
|
||||||
|
p.setPathEffect(new SkDashPathEffect(intervals, 2, phase, false));
|
||||||
|
|
||||||
|
SkPoint pts[2];
|
||||||
|
|
||||||
|
for (int y = 0; y < 100; y += 5) {
|
||||||
|
pts[0].set(0, SkIntToScalar(y));
|
||||||
|
pts[1].set(length, SkIntToScalar(y));
|
||||||
|
|
||||||
|
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setAntiAlias(true);
|
||||||
|
|
||||||
|
for (int x = 0; x < 100; x += 7) {
|
||||||
|
pts[0].set(SkIntToScalar(x), 0);
|
||||||
|
pts[1].set(SkIntToScalar(x), length);
|
||||||
|
|
||||||
|
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onDraw(SkCanvas* canvas) {
|
||||||
|
// fast path should work on this run
|
||||||
|
canvas->save();
|
||||||
|
this->drawDashedLines(canvas, 100, SK_Scalar1);
|
||||||
|
canvas->restore();
|
||||||
|
|
||||||
|
// non-1 phase should break the fast path
|
||||||
|
canvas->save();
|
||||||
|
canvas->translate(110, 0);
|
||||||
|
this->drawDashedLines(canvas, 100, SK_ScalarHalf);
|
||||||
|
canvas->restore();
|
||||||
|
|
||||||
|
// non-integer length should break the fast path
|
||||||
|
canvas->save();
|
||||||
|
canvas->translate(220, 0);
|
||||||
|
this->drawDashedLines(canvas, 99.5, SK_ScalarHalf);
|
||||||
|
canvas->restore();
|
||||||
|
|
||||||
|
// rotation should break the fast path
|
||||||
|
canvas->save();
|
||||||
|
canvas->translate(110+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
|
||||||
|
canvas->rotate(45);
|
||||||
|
canvas->translate(-50, -50);
|
||||||
|
|
||||||
|
this->drawDashedLines(canvas, 100, SK_Scalar1);
|
||||||
|
canvas->restore();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static skiagm::GM* F0(void*) { return new DashingGM; }
|
static skiagm::GM* F0(void*) { return new DashingGM; }
|
||||||
static skiagm::GM* F1(void*) { return new Dashing2GM; }
|
static skiagm::GM* F1(void*) { return new Dashing2GM; }
|
||||||
|
static skiagm::GM* F2(void*) { return new Dashing3GM; }
|
||||||
|
|
||||||
static skiagm::GMRegistry gR0(F0);
|
static skiagm::GMRegistry gR0(F0);
|
||||||
static skiagm::GMRegistry gR1(F1);
|
static skiagm::GMRegistry gR1(F1);
|
||||||
|
static skiagm::GMRegistry gR2(F2);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
|
|
||||||
#include "SkFlattenable.h"
|
#include "SkFlattenable.h"
|
||||||
#include "SkPaint.h"
|
#include "SkPaint.h"
|
||||||
|
#include "SkPath.h"
|
||||||
|
#include "SkPoint.h"
|
||||||
|
#include "SkRect.h"
|
||||||
|
#include "SkTDArray.h"
|
||||||
|
|
||||||
class SkPath;
|
class SkPath;
|
||||||
|
|
||||||
|
@ -129,6 +133,47 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void computeFastBounds(SkRect* dst, const SkRect& src);
|
virtual void computeFastBounds(SkRect* dst, const SkRect& src);
|
||||||
|
|
||||||
|
/** \class PointData
|
||||||
|
|
||||||
|
PointData aggregates all the information needed to draw the point
|
||||||
|
primitives returned by an 'asPoints' call.
|
||||||
|
*/
|
||||||
|
class PointData {
|
||||||
|
public:
|
||||||
|
PointData()
|
||||||
|
: fFlags(0) {
|
||||||
|
fSize.set(SK_Scalar1, SK_Scalar1);
|
||||||
|
// 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets
|
||||||
|
// the kUseClip flag
|
||||||
|
};
|
||||||
|
~PointData() {};
|
||||||
|
|
||||||
|
// TODO: consider using passed-in flags to limit the work asPoints does.
|
||||||
|
// For example, a kNoPath flag could indicate don't bother generating
|
||||||
|
// stamped solutions.
|
||||||
|
|
||||||
|
// Currently none of these flags are supported.
|
||||||
|
enum PointFlags {
|
||||||
|
kCircles_PointFlag = 0x01, // draw points as circles (instead of rects)
|
||||||
|
kUsePath_PointFlag = 0x02, // draw points as stamps of the returned path
|
||||||
|
kUseClip_PointFlag = 0x04, // apply 'fClipRect' before drawing the points
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t fFlags; // flags that impact the drawing of the points
|
||||||
|
// TODO: consider replacing the TDArray with either SkData or a ptr/len field
|
||||||
|
SkTDArray<SkPoint> fPoints; // the center point of each generated point
|
||||||
|
SkVector fSize; // the size to draw the points
|
||||||
|
SkRect fClipRect; // clip required to draw the points (if kUseClip is set)
|
||||||
|
SkPath fPath; // 'stamp' to be used at each point (if kUsePath is set)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does applying this path effect to 'src' yield a set of points? If so,
|
||||||
|
* optionally return the points in 'results'.
|
||||||
|
*/
|
||||||
|
virtual bool asPoints(PointData* results, const SkPath& src,
|
||||||
|
const SkStrokeRec&, const SkMatrix&) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SkPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
|
SkPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,9 @@ public:
|
||||||
|
|
||||||
virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) SK_OVERRIDE;
|
virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) SK_OVERRIDE;
|
||||||
|
|
||||||
|
virtual bool asPoints(PointData* results, const SkPath& src,
|
||||||
|
const SkStrokeRec&, const SkMatrix&) const SK_OVERRIDE;
|
||||||
|
|
||||||
// overrides for SkFlattenable
|
// overrides for SkFlattenable
|
||||||
// This method is not exported to java.
|
// This method is not exported to java.
|
||||||
virtual Factory getFactory();
|
virtual Factory getFactory();
|
||||||
|
|
|
@ -635,6 +635,39 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SkCanvas::kLines_PointMode:
|
case SkCanvas::kLines_PointMode:
|
||||||
|
#ifndef SK_DISABLE_DASHING_OPTIMIZATION
|
||||||
|
if (2 == count && NULL != paint.getPathEffect()) {
|
||||||
|
// most likely a dashed line - see if it is one of the ones
|
||||||
|
// we can accelerate
|
||||||
|
SkStrokeRec rec(paint);
|
||||||
|
SkPathEffect::PointData dst;
|
||||||
|
|
||||||
|
SkPath path;
|
||||||
|
path.moveTo(pts[0]);
|
||||||
|
path.lineTo(pts[1]);
|
||||||
|
|
||||||
|
if (paint.getPathEffect()->asPoints(&dst, path, rec, *fMatrix) &&
|
||||||
|
SK_Scalar1 == dst.fSize.fX && SK_Scalar1 == dst.fSize.fY &&
|
||||||
|
!(SkPathEffect::PointData::kUsePath_PointFlag & dst.fFlags)) {
|
||||||
|
SkPaint newP(paint);
|
||||||
|
newP.setPathEffect(NULL);
|
||||||
|
|
||||||
|
if (SkPathEffect::PointData::kCircles_PointFlag & dst.fFlags) {
|
||||||
|
newP.setStrokeCap(SkPaint::kRound_Cap);
|
||||||
|
} else {
|
||||||
|
newP.setStrokeCap(SkPaint::kButt_Cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->drawPoints(SkCanvas::kPoints_PointMode,
|
||||||
|
dst.fPoints.count(),
|
||||||
|
dst.fPoints.begin(),
|
||||||
|
newP,
|
||||||
|
forceUseDevice);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // DISABLE_DASHING_OPTIMIZATION
|
||||||
|
// couldn't take fast path so fall through!
|
||||||
case SkCanvas::kPolygon_PointMode: {
|
case SkCanvas::kPolygon_PointMode: {
|
||||||
count -= 1;
|
count -= 1;
|
||||||
SkPath path;
|
SkPath path;
|
||||||
|
|
|
@ -116,6 +116,11 @@ void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) {
|
||||||
*dst = src;
|
*dst = src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkPathEffect::asPoints(PointData* results, const SkPath& src,
|
||||||
|
const SkStrokeRec&, const SkMatrix&) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
|
SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
|
||||||
|
|
|
@ -227,6 +227,82 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Currently asPoints is more restrictive then it needs to be. In the future
|
||||||
|
// we need to:
|
||||||
|
// allow kRound_Cap capping (could allow rotations in the matrix with this)
|
||||||
|
// loosen restriction on initial dash length
|
||||||
|
// allow cases where (stroke width == interval[0]) and return size
|
||||||
|
// allow partial first and last pixels
|
||||||
|
bool SkDashPathEffect::asPoints(PointData* results,
|
||||||
|
const SkPath& src,
|
||||||
|
const SkStrokeRec& rec,
|
||||||
|
const SkMatrix& matrix) const {
|
||||||
|
if (rec.isFillStyle() || fInitialDashLength < 0 || SK_Scalar1 != rec.getWidth()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fIntervalLength != 2 || SK_Scalar1 != fIntervals[0] || SK_Scalar1 != fIntervals[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fScaleToFit || 0 != fInitialDashLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPoint pts[2];
|
||||||
|
|
||||||
|
if (rec.isHairlineStyle() || !src.isLine(pts)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SkPaint::kButt_Cap != rec.getCap()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matrix.rectStaysRect()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPathMeasure meas(src, false);
|
||||||
|
SkScalar length = meas.getLength();
|
||||||
|
|
||||||
|
if (!SkScalarIsInt(length)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != results) {
|
||||||
|
results->fFlags = 0; // don't use clip rect & draw rects
|
||||||
|
results->fSize.set(SK_Scalar1, SK_Scalar1);
|
||||||
|
|
||||||
|
SkVector tangent = pts[1] - pts[0];
|
||||||
|
if (tangent.isZero()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tangent.scale(SkScalarInvert(length));
|
||||||
|
|
||||||
|
SkScalar ptCount = SkScalarDiv(length, SkIntToScalar(2));
|
||||||
|
results->fPoints.setReserve(SkScalarCeilToInt(ptCount));
|
||||||
|
|
||||||
|
// +1 b.c. fInitialDashLength is zero so the initial segment will be skipped
|
||||||
|
int index = fInitialDashIndex+1;
|
||||||
|
|
||||||
|
for (SkScalar distance = SK_ScalarHalf; distance < length; distance += SK_Scalar1) {
|
||||||
|
SkASSERT(index <= fCount);
|
||||||
|
|
||||||
|
if (0 == index) {
|
||||||
|
SkScalar x0 = pts[0].fX + SkScalarMul(tangent.fX, distance);
|
||||||
|
SkScalar y0 = pts[0].fY + SkScalarMul(tangent.fY, distance);
|
||||||
|
results->fPoints.append()->set(x0, y0);
|
||||||
|
}
|
||||||
|
|
||||||
|
index ^= 1; // 0 -> 1 -> 0 ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SkFlattenable::Factory SkDashPathEffect::getFactory() {
|
SkFlattenable::Factory SkDashPathEffect::getFactory() {
|
||||||
return fInitialDashLength < 0 ? NULL : CreateProc;
|
return fInitialDashLength < 0 ? NULL : CreateProc;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче