Add asADash entry point into SkPathEffect to allow extracting Dash info from PathEffects

BUG=skia:
R=bsalomon@google.com, reed@google.com

Author: egdaniel@google.com

Review URL: https://codereview.chromium.org/212103010

git-svn-id: http://skia.googlecode.com/svn/trunk@14297 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-04-22 15:21:18 +00:00
parent fd4ee4dea1
commit aec143824c
7 changed files with 149 additions and 24 deletions

View File

@ -34,6 +34,7 @@
'../tests/ARGBImageEncoderTest.cpp',
'../tests/AndroidPaintTest.cpp',
'../tests/AnnotationTest.cpp',
'../tests/AsADashTest.cpp',
'../tests/AtomicTest.cpp',
'../tests/BBoxHierarchyTest.cpp',
'../tests/BitSetTest.cpp',

View File

@ -104,6 +104,33 @@ public:
const SkStrokeRec&, const SkMatrix&,
const SkRect* cullR) const;
/**
* If the PathEffect can be represented as a dash pattern, asADash will return kDash_DashType
* and None otherwise. If a non NULL info is passed in, the various DashInfo will be filled
* in if the PathEffect can be a dash pattern. If passed in info has an fCount equal or
* greater to that of the effect, it will memcpy the values of the dash intervals into the
* info. Thus the general approach will be call asADash once with default info to get DashType
* and fCount. If effect can be represented as a dash pattern, allocate space for the intervals
* in info, then call asADash again with the same info and the intervals will get copied in.
*/
enum DashType {
kNone_DashType, //!< ignores the info parameter
kDash_DashType, //!< fills in all of the info parameter
};
struct DashInfo {
DashInfo() : fIntervals(NULL), fCount(0), fPhase(0) {}
SkScalar* fIntervals; //!< Length of on/off intervals for dashed lines
// Even values represent ons, and odds offs
int32_t fCount; //!< Number of intervals in the dash. Should be even number
SkScalar fPhase; //!< Offset into the dashed interval pattern
// mod the sum of all intervals
};
virtual DashType asADash(DashInfo* info) const;
SK_DEFINE_FLATTENABLE_TYPE(SkPathEffect)
protected:

View File

@ -324,13 +324,14 @@ protected:
// V22: SK_PICT_FACTORY_TAG's size is now the chunk size in bytes
// V23: SkPaint::FilterLevel became a real enum
// V24: SkTwoPointConicalGradient now has fFlipped flag for gradient flipping
// V25: SkDashPathEffect now only writes phase and interval array when flattening
// Note: If the picture version needs to be increased then please follow the
// steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 19;
static const uint32_t CURRENT_PICTURE_VERSION = 24;
static const uint32_t CURRENT_PICTURE_VERSION = 25;
mutable uint32_t fUniqueID;

View File

@ -49,6 +49,8 @@ public:
const SkStrokeRec&, const SkMatrix&,
const SkRect*) const SK_OVERRIDE;
virtual DashType asADash(DashInfo* info) const SK_OVERRIDE;
virtual Factory getFactory() const SK_OVERRIDE;
static SkFlattenable* CreateProc(SkReadBuffer&);
@ -63,8 +65,11 @@ public:
SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase);
private:
void setInternalMembers(SkScalar phase);
SkScalar* fIntervals;
int32_t fCount;
SkScalar fPhase;
// computed from phase
SkScalar fInitialDashLength;
int32_t fInitialDashIndex;

View File

@ -22,6 +22,10 @@ bool SkPathEffect::asPoints(PointData* results, const SkPath& src,
return false;
}
SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const {
return kNone_DashType;
}
///////////////////////////////////////////////////////////////////////////////
SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)

View File

@ -34,19 +34,10 @@ static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase,
return intervals[0];
}
SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
SkScalar phase) {
SkASSERT(intervals);
SkASSERT(count > 1 && SkAlign2(count) == count);
fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
fCount = count;
void SkDashPathEffect::setInternalMembers(SkScalar phase) {
SkScalar len = 0;
for (int i = 0; i < count; i++) {
SkASSERT(intervals[i] >= 0);
fIntervals[i] = intervals[i];
len += intervals[i];
for (int i = 0; i < fCount; i++) {
len += fIntervals[i];
}
fIntervalLength = len;
@ -74,8 +65,10 @@ SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
}
SkASSERT(phase >= 0 && phase < len);
fInitialDashLength = FindFirstInterval(intervals, phase,
&fInitialDashIndex, count);
fPhase = phase;
fInitialDashLength = FindFirstInterval(fIntervals, fPhase,
&fInitialDashIndex, fCount);
SkASSERT(fInitialDashLength >= 0);
SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
@ -84,6 +77,21 @@ SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
}
}
SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
SkScalar phase) {
SkASSERT(intervals);
SkASSERT(count > 1 && SkAlign2(count) == count);
fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
fCount = count;
for (int i = 0; i < count; i++) {
SkASSERT(intervals[i] >= 0);
fIntervals[i] = intervals[i];
}
this->setInternalMembers(phase);
}
SkDashPathEffect::~SkDashPathEffect() {
sk_free(fIntervals);
}
@ -510,17 +518,24 @@ bool SkDashPathEffect::asPoints(PointData* results,
return true;
}
SkPathEffect::DashType SkDashPathEffect::asADash(DashInfo* info) const {
if (info) {
if (info->fCount >= fCount && NULL != info->fIntervals) {
memcpy(info->fIntervals, fIntervals, fCount * sizeof(SkScalar));
}
info->fCount = fCount;
info->fPhase = fPhase;
}
return kDash_DashType;
}
SkFlattenable::Factory SkDashPathEffect::getFactory() const {
return CreateProc;
}
void SkDashPathEffect::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeInt(fInitialDashIndex);
buffer.writeScalar(fInitialDashLength);
buffer.writeScalar(fIntervalLength);
// Dummy write to stay compatible with old skps. Write will be removed in follow up patch.
buffer.writeBool(false);
buffer.writeScalar(fPhase);
buffer.writeScalarArray(fIntervals, fCount);
}
@ -529,10 +544,15 @@ SkFlattenable* SkDashPathEffect::CreateProc(SkReadBuffer& buffer) {
}
SkDashPathEffect::SkDashPathEffect(SkReadBuffer& buffer) : INHERITED(buffer) {
fInitialDashIndex = buffer.readInt();
fInitialDashLength = buffer.readScalar();
fIntervalLength = buffer.readScalar();
buffer.readBool(); // dummy read to stay compatible with old skps
bool useOldPic = buffer.pictureVersion() < 25 && 0 != buffer.pictureVersion();
if (useOldPic) {
fInitialDashIndex = buffer.readInt();
fInitialDashLength = buffer.readScalar();
fIntervalLength = buffer.readScalar();
buffer.readBool(); // Dummy for old ScalarToFit field
} else {
fPhase = buffer.readScalar();
}
fCount = buffer.getArrayCount();
size_t allocSize = sizeof(SkScalar) * fCount;
@ -542,4 +562,14 @@ SkDashPathEffect::SkDashPathEffect(SkReadBuffer& buffer) : INHERITED(buffer) {
} else {
fIntervals = NULL;
}
if (useOldPic) {
fPhase = 0;
for (int i = 0; i < fInitialDashIndex; ++i) {
fPhase += fIntervals[i];
}
fPhase += fInitialDashLength;
} else {
this->setInternalMembers(fPhase);
}
}

57
tests/AsADashTest.cpp Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Test.h"
#include "SkPathEffect.h"
#include "SkDashPathEffect.h"
#include "SkCornerPathEffect.h"
DEF_TEST(AsADashTest_noneDash, reporter) {
SkAutoTUnref<SkCornerPathEffect> pe(SkCornerPathEffect::Create(1.0));
SkPathEffect::DashInfo info;
SkPathEffect::DashType dashType = pe->asADash(&info);
REPORTER_ASSERT(reporter, SkPathEffect::kNone_DashType == dashType);
}
DEF_TEST(AsADashTest_nullInfo, reporter) {
SkScalar inIntervals[] = { 4.0, 2.0, 1.0, 3.0 };
const SkScalar phase = 2.0;
SkAutoTUnref<SkDashPathEffect> pe(SkDashPathEffect::Create(inIntervals, 4, phase));
SkPathEffect::DashType dashType = pe->asADash(NULL);
REPORTER_ASSERT(reporter, SkPathEffect::kDash_DashType == dashType);
}
DEF_TEST(AsADashTest_usingDash, reporter) {
SkScalar inIntervals[] = { 4.0, 2.0, 1.0, 3.0 };
SkScalar totalIntSum = 10.0;
const SkScalar phase = 2.0;
SkAutoTUnref<SkDashPathEffect> pe(SkDashPathEffect::Create(inIntervals, 4, phase));
SkPathEffect::DashInfo info;
SkPathEffect::DashType dashType = pe->asADash(&info);
REPORTER_ASSERT(reporter, SkPathEffect::kDash_DashType == dashType);
REPORTER_ASSERT(reporter, 4 == info.fCount);
REPORTER_ASSERT(reporter, SkScalarMod(phase, totalIntSum) == info.fPhase);
// Since it is a kDash_DashType, allocate space for the intervals and recall asADash
SkAutoTArray<SkScalar> intervals(info.fCount);
info.fIntervals = intervals.get();
pe->asADash(&info);
REPORTER_ASSERT(reporter, inIntervals[0] == info.fIntervals[0]);
REPORTER_ASSERT(reporter, inIntervals[1] == info.fIntervals[1]);
REPORTER_ASSERT(reporter, inIntervals[2] == info.fIntervals[2]);
REPORTER_ASSERT(reporter, inIntervals[3] == info.fIntervals[3]);
// Make sure nothing else has changed on us
REPORTER_ASSERT(reporter, 4 == info.fCount);
REPORTER_ASSERT(reporter, SkScalarMod(phase, totalIntSum) == info.fPhase);
}