new scanconversion technique
This technique geometrically clips all segments against the clip bounds, ensuring that we never send a value to the edgelist that might overflow in fixedpoint. Current disabled in SkScan_Path.cpp by a #define. There are a few minor pixel differences between this and the old technique, as found by the gm tool, so at the moment this new code is off by default. git-svn-id: http://skia.googlecode.com/svn/trunk@432 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
bb13586591
commit
909994fbae
58
include/core/SkEdgeClipper.h
Normal file
58
include/core/SkEdgeClipper.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SkEdgeClipper_DEFINED
|
||||
#define SkEdgeClipper_DEFINED
|
||||
|
||||
#include "SkPath.h"
|
||||
|
||||
/** This is basically an iterator. It is initialized with an edge and a clip,
|
||||
and then next() is called until it returns kDone_Verb.
|
||||
*/
|
||||
class SkEdgeClipper {
|
||||
public:
|
||||
bool clipQuad(const SkPoint pts[3], const SkRect& clip);
|
||||
bool clipCubic(const SkPoint pts[4], const SkRect& clip);
|
||||
|
||||
SkPath::Verb next(SkPoint pts[]);
|
||||
|
||||
private:
|
||||
SkPoint* fCurrPoint;
|
||||
SkPath::Verb* fCurrVerb;
|
||||
|
||||
enum {
|
||||
kMaxVerbs = 13,
|
||||
kMaxPoints = 32
|
||||
};
|
||||
SkPoint fPoints[kMaxPoints];
|
||||
SkPath::Verb fVerbs[kMaxVerbs];
|
||||
|
||||
void clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip);
|
||||
void clipMonoCubic(const SkPoint srcPts[4], const SkRect& clip);
|
||||
void appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse);
|
||||
void appendQuad(const SkPoint pts[3], bool reverse);
|
||||
void appendCubic(const SkPoint pts[4], bool reverse);
|
||||
};
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void sk_assert_monotonic_x(const SkPoint pts[], int count);
|
||||
void sk_assert_monotonic_y(const SkPoint pts[], int count);
|
||||
#else
|
||||
#define sk_assert_monotonic_x(pts, count)
|
||||
#define sk_assert_monotonic_y(pts, count)
|
||||
#endif
|
||||
|
||||
#endif
|
@ -57,8 +57,8 @@ int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValues[1]);
|
||||
/** Given 3 points on a quadratic bezier, chop it into 1, 2 beziers such that
|
||||
the resulting beziers are monotonic in Y. This is called by the scan converter.
|
||||
Depending on what is returned, dst[] is treated as follows
|
||||
1 dst[0..2] is the original quad
|
||||
2 dst[0..2] and dst[2..4] are the two new quads
|
||||
0 dst[0..2] is the original quad
|
||||
1 dst[0..2] and dst[2..4] are the two new quads
|
||||
*/
|
||||
int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]);
|
||||
int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5]);
|
||||
@ -110,12 +110,13 @@ int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar
|
||||
/** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
|
||||
the resulting beziers are monotonic in Y. This is called by the scan converter.
|
||||
Depending on what is returned, dst[] is treated as follows
|
||||
1 dst[0..3] is the original cubic
|
||||
2 dst[0..3] and dst[3..6] are the two new cubics
|
||||
3 dst[0..3], dst[3..6], dst[6..9] are the three new cubics
|
||||
0 dst[0..3] is the original cubic
|
||||
1 dst[0..3] and dst[3..6] are the two new cubics
|
||||
2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics
|
||||
If dst == null, it is ignored and only the count is returned.
|
||||
*/
|
||||
int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]);
|
||||
int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]);
|
||||
|
||||
/** Given a cubic bezier, return 0, 1, or 2 t-values that represent the
|
||||
inflection points.
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "SkRandom.h"
|
||||
|
||||
#include "SkLineClipper.h"
|
||||
#include "SkQuadClipper.h"
|
||||
#include "SkEdgeClipper.h"
|
||||
|
||||
static void drawQuad(SkCanvas* canvas, const SkPoint pts[3], const SkPaint& p) {
|
||||
SkPath path;
|
||||
@ -63,7 +63,7 @@ static void quad_clipper(const SkPoint src[], const SkRect& clip,
|
||||
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
|
||||
drawQuad(canvas, src, p1);
|
||||
|
||||
SkQuadClipper2 clipper;
|
||||
SkEdgeClipper clipper;
|
||||
if (clipper.clipQuad(src, clip)) {
|
||||
SkPoint pts[3];
|
||||
SkPath::Verb verb;
|
||||
@ -88,7 +88,7 @@ static void cubic_clipper(const SkPoint src[], const SkRect& clip,
|
||||
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
|
||||
drawCubic(canvas, src, p1);
|
||||
|
||||
SkQuadClipper2 clipper;
|
||||
SkEdgeClipper clipper;
|
||||
if (clipper.clipCubic(src, clip)) {
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb verb;
|
||||
|
154
src/core/SkEdgeBuilder.cpp
Normal file
154
src/core/SkEdgeBuilder.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include "SkEdgeBuilder.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkEdge.h"
|
||||
#include "SkEdgeClipper.h"
|
||||
#include "SkLineClipper.h"
|
||||
#include "SkGeometry.h"
|
||||
|
||||
SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {}
|
||||
|
||||
template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
|
||||
return static_cast<T*>(alloc.allocThrow(sizeof(T)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkEdgeBuilder::addLine(const SkPoint pts[]) {
|
||||
SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
|
||||
if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) {
|
||||
fList.push(edge);
|
||||
} else {
|
||||
// TODO: unallocate edge from storage...
|
||||
}
|
||||
}
|
||||
|
||||
void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
|
||||
SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc);
|
||||
if (edge->setQuadratic(pts, fShiftUp)) {
|
||||
fList.push(edge);
|
||||
} else {
|
||||
// TODO: unallocate edge from storage...
|
||||
}
|
||||
}
|
||||
|
||||
void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
|
||||
SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc);
|
||||
if (edge->setCubic(pts, NULL, fShiftUp)) {
|
||||
fList.push(edge);
|
||||
} else {
|
||||
// TODO: unallocate edge from storage...
|
||||
}
|
||||
}
|
||||
|
||||
void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb verb;
|
||||
|
||||
while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
this->addLine(pts);
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
this->addQuad(pts);
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
this->addCubic(pts);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
|
||||
dst->set(SkIntToScalar(src.fLeft >> shift),
|
||||
SkIntToScalar(src.fTop >> shift),
|
||||
SkIntToScalar(src.fRight >> shift),
|
||||
SkIntToScalar(src.fBottom >> shift));
|
||||
}
|
||||
|
||||
int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
|
||||
int shiftUp) {
|
||||
fAlloc.reset();
|
||||
fList.reset();
|
||||
fShiftUp = shiftUp;
|
||||
|
||||
SkPath::Iter iter(path, true);
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb verb;
|
||||
|
||||
if (iclip) {
|
||||
SkRect clip;
|
||||
setShiftedClip(&clip, *iclip, shiftUp);
|
||||
SkEdgeClipper clipper;
|
||||
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
case SkPath::kClose_Verb:
|
||||
// we ignore these, and just get the whole segment from
|
||||
// the corresponding line/quad/cubic verbs
|
||||
break;
|
||||
case SkPath::kLine_Verb: {
|
||||
SkPoint lines[SkLineClipper::kMaxPoints];
|
||||
int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
this->addLine(&lines[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SkPath::kQuad_Verb:
|
||||
if (clipper.clipQuad(pts, clip)) {
|
||||
this->addClipper(&clipper);
|
||||
}
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
if (clipper.clipCubic(pts, clip)) {
|
||||
this->addClipper(&clipper);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"unexpected verb");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
case SkPath::kClose_Verb:
|
||||
// we ignore these, and just get the whole segment from
|
||||
// the corresponding line/quad/cubic verbs
|
||||
break;
|
||||
case SkPath::kLine_Verb:
|
||||
this->addLine(pts);
|
||||
break;
|
||||
case SkPath::kQuad_Verb: {
|
||||
SkPoint monoX[5];
|
||||
int n = SkChopQuadAtYExtrema(pts, monoX);
|
||||
for (int i = 0; i <= n; i++) {
|
||||
this->addQuad(&monoX[i * 2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SkPath::kCubic_Verb: {
|
||||
SkPoint monoY[10];
|
||||
int n = SkChopCubicAtYExtrema(pts, monoY);
|
||||
for (int i = 0; i <= n; i++) {
|
||||
this->addCubic(&monoY[i * 3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SkASSERT(!"unexpected verb");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fList.count();
|
||||
}
|
||||
|
||||
|
31
src/core/SkEdgeBuilder.h
Normal file
31
src/core/SkEdgeBuilder.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef SkEdgeBuilder_DEFINED
|
||||
#define SkEdgeBuilder_DEFINED
|
||||
|
||||
#include "SkChunkAlloc.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkTDArray.h"
|
||||
|
||||
class SkEdge;
|
||||
class SkEdgeClipper;
|
||||
class SkPath;
|
||||
|
||||
class SkEdgeBuilder {
|
||||
public:
|
||||
SkEdgeBuilder();
|
||||
|
||||
int build(const SkPath& path, const SkIRect* clip, int shiftUp);
|
||||
|
||||
SkEdge** edgeList() { return fList.begin(); }
|
||||
|
||||
private:
|
||||
SkChunkAlloc fAlloc;
|
||||
SkTDArray<SkEdge*> fList;
|
||||
int fShiftUp;
|
||||
|
||||
void addLine(const SkPoint pts[]);
|
||||
void addQuad(const SkPoint pts[]);
|
||||
void addCubic(const SkPoint pts[]);
|
||||
void addClipper(SkEdgeClipper*);
|
||||
};
|
||||
|
||||
#endif
|
508
src/core/SkEdgeClipper.cpp
Normal file
508
src/core/SkEdgeClipper.cpp
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SkEdgeClipper.h"
|
||||
#include "SkGeometry.h"
|
||||
|
||||
static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
|
||||
return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
|
||||
}
|
||||
|
||||
static inline void clamp_le(SkScalar& value, SkScalar max) {
|
||||
if (value > max) {
|
||||
value = max;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void clamp_ge(SkScalar& value, SkScalar min) {
|
||||
if (value < min) {
|
||||
value = min;
|
||||
}
|
||||
}
|
||||
|
||||
/* src[] must be monotonic in Y. This routine copies src into dst, and sorts
|
||||
it to be increasing in Y. If it had to reverse the order of the points,
|
||||
it returns true, otherwise it returns false
|
||||
*/
|
||||
static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
|
||||
// we need the data to be monotonically increasing in Y
|
||||
if (src[0].fY > src[count - 1].fY) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
dst[i] = src[count - i - 1];
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
memcpy(dst, src, count * sizeof(SkPoint));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
|
||||
SkScalar target, SkScalar* t) {
|
||||
/* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
|
||||
* We solve for t, using quadratic equation, hence we have to rearrange
|
||||
* our cooefficents to look like At^2 + Bt + C
|
||||
*/
|
||||
SkScalar A = c0 - c1 - c1 + c2;
|
||||
SkScalar B = 2*(c1 - c0);
|
||||
SkScalar C = c0 - target;
|
||||
|
||||
SkScalar roots[2]; // we only expect one, but make room for 2 for safety
|
||||
int count = SkFindUnitQuadRoots(A, B, C, roots);
|
||||
if (count) {
|
||||
*t = roots[0];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
|
||||
return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
|
||||
}
|
||||
|
||||
static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
|
||||
return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
|
||||
}
|
||||
|
||||
// Modify pts[] in place so that it is clipped in Y to the clip rect
|
||||
static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
|
||||
SkScalar t;
|
||||
SkPoint tmp[5]; // for SkChopQuadAt
|
||||
|
||||
// are we partially above
|
||||
if (pts[0].fY < clip.fTop) {
|
||||
if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
|
||||
// take the 2nd chopped quad
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
clamp_ge(tmp[2].fY, clip.fTop);
|
||||
clamp_ge(tmp[3].fY, clip.fTop);
|
||||
pts[0] = tmp[2];
|
||||
pts[1] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the top
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pts[i].fY < clip.fTop) {
|
||||
pts[i].fY = clip.fTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially below
|
||||
if (pts[2].fY > clip.fBottom) {
|
||||
if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fY, clip.fBottom);
|
||||
clamp_le(tmp[2].fY, clip.fBottom);
|
||||
pts[1] = tmp[1];
|
||||
pts[2] = tmp[2];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the bottom
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pts[i].fY > clip.fBottom) {
|
||||
pts[i].fY = clip.fBottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// srcPts[] must be monotonic in X and Y
|
||||
void SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
SkPoint pts[3];
|
||||
bool reverse = sort_increasing_Y(pts, srcPts, 3);
|
||||
|
||||
// are we completely above or below
|
||||
if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now chop so that pts is contained within clip in Y
|
||||
chop_quad_in_Y(pts, clip);
|
||||
|
||||
if (pts[0].fX > pts[2].fX) {
|
||||
SkTSwap<SkPoint>(pts[0], pts[2]);
|
||||
reverse = !reverse;
|
||||
}
|
||||
SkASSERT(pts[0].fX <= pts[1].fX);
|
||||
SkASSERT(pts[1].fX <= pts[2].fX);
|
||||
|
||||
// Now chop in X has needed, and record the segments
|
||||
|
||||
if (pts[2].fX <= clip.fLeft) { // wholly to the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
|
||||
return;
|
||||
}
|
||||
if (pts[0].fX >= clip.fRight) { // wholly to the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar t;
|
||||
SkPoint tmp[5]; // for SkChopQuadAt
|
||||
|
||||
// are we partially to the left
|
||||
if (pts[0].fX < clip.fLeft) {
|
||||
if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
|
||||
clamp_ge(tmp[2].fX, clip.fLeft);
|
||||
clamp_ge(tmp[3].fX, clip.fLeft);
|
||||
pts[0] = tmp[2];
|
||||
pts[1] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially to the right
|
||||
if (pts[2].fX > clip.fRight) {
|
||||
if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fX, clip.fRight);
|
||||
clamp_le(tmp[2].fX, clip.fRight);
|
||||
this->appendQuad(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
} else { // wholly inside the clip
|
||||
this->appendQuad(pts, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
|
||||
SkRect bounds;
|
||||
bounds.set(srcPts, 3);
|
||||
|
||||
if (!quick_reject(bounds, clip)) {
|
||||
SkPoint monoY[5];
|
||||
int countY = SkChopQuadAtYExtrema(srcPts, monoY);
|
||||
for (int y = 0; y <= countY; y++) {
|
||||
SkPoint monoX[5];
|
||||
int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
|
||||
for (int x = 0; x <= countX; x++) {
|
||||
this->clipMonoQuad(&monoX[x * 2], clip);
|
||||
SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
|
||||
SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fCurrVerb = SkPath::kDone_Verb;
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
return SkPath::kDone_Verb != fVerbs[0];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
|
||||
SkScalar D, SkScalar t) {
|
||||
return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
|
||||
}
|
||||
|
||||
/* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
|
||||
t value such that cubic(t) = target
|
||||
*/
|
||||
static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
|
||||
SkScalar target, SkScalar* t) {
|
||||
// SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
|
||||
SkASSERT(c0 < target && target < c3);
|
||||
|
||||
SkScalar D = c0;
|
||||
SkScalar A = c3 + 3*(c1 - c2) - c0;
|
||||
SkScalar B = 3*(c2 - c1 - c1 + c0);
|
||||
SkScalar C = 3*(c1 - c0);
|
||||
|
||||
SkScalar minT = 0;
|
||||
SkScalar maxT = SK_Scalar1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
SkScalar mid = SkScalarAve(minT, maxT);
|
||||
SkScalar coord = eval_cubic_coeff(A, B, C, D, mid);
|
||||
if (coord < target) {
|
||||
minT = mid;
|
||||
} else {
|
||||
maxT = mid;
|
||||
}
|
||||
}
|
||||
*t = SkScalarAve(minT, maxT);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) {
|
||||
return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t);
|
||||
}
|
||||
|
||||
static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
|
||||
return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t);
|
||||
}
|
||||
|
||||
// Modify pts[] in place so that it is clipped in Y to the clip rect
|
||||
static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
|
||||
SkScalar t;
|
||||
SkPoint tmp[7]; // for SkChopCubicAt
|
||||
|
||||
// are we partially above
|
||||
if (pts[0].fY < clip.fTop) {
|
||||
if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
clamp_ge(tmp[3].fY, clip.fTop);
|
||||
clamp_ge(tmp[4].fY, clip.fTop);
|
||||
clamp_ge(tmp[5].fY, clip.fTop);
|
||||
pts[0] = tmp[3];
|
||||
pts[1] = tmp[4];
|
||||
pts[2] = tmp[5];
|
||||
} else {
|
||||
// if chopMonoCubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the top
|
||||
for (int i = 0; i < 4; i++) {
|
||||
clamp_ge(pts[i].fY, clip.fTop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially below
|
||||
if (pts[3].fY > clip.fBottom) {
|
||||
if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fY, clip.fBottom);
|
||||
clamp_le(tmp[2].fY, clip.fBottom);
|
||||
clamp_le(tmp[3].fY, clip.fBottom);
|
||||
pts[1] = tmp[1];
|
||||
pts[2] = tmp[2];
|
||||
pts[3] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoCubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the bottom
|
||||
for (int i = 0; i < 4; i++) {
|
||||
clamp_le(pts[i].fY, clip.fBottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// srcPts[] must be monotonic in X and Y
|
||||
void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
|
||||
SkPoint pts[4];
|
||||
bool reverse = sort_increasing_Y(pts, src, 4);
|
||||
|
||||
// are we completely above or below
|
||||
if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now chop so that pts is contained within clip in Y
|
||||
chop_cubic_in_Y(pts, clip);
|
||||
|
||||
if (pts[0].fX > pts[3].fX) {
|
||||
SkTSwap<SkPoint>(pts[0], pts[3]);
|
||||
SkTSwap<SkPoint>(pts[1], pts[2]);
|
||||
reverse = !reverse;
|
||||
}
|
||||
|
||||
// Now chop in X has needed, and record the segments
|
||||
|
||||
if (pts[3].fX <= clip.fLeft) { // wholly to the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
|
||||
return;
|
||||
}
|
||||
if (pts[0].fX >= clip.fRight) { // wholly to the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar t;
|
||||
SkPoint tmp[7];
|
||||
|
||||
// are we partially to the left
|
||||
if (pts[0].fX < clip.fLeft) {
|
||||
if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
|
||||
clamp_ge(tmp[3].fX, clip.fLeft);
|
||||
clamp_ge(tmp[4].fX, clip.fLeft);
|
||||
clamp_ge(tmp[5].fX, clip.fLeft);
|
||||
pts[0] = tmp[3];
|
||||
pts[1] = tmp[4];
|
||||
pts[2] = tmp[5];
|
||||
} else {
|
||||
// if chopMonocubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially to the right
|
||||
if (pts[3].fX > clip.fRight) {
|
||||
if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fX, clip.fRight);
|
||||
clamp_le(tmp[2].fX, clip.fRight);
|
||||
clamp_le(tmp[3].fX, clip.fRight);
|
||||
this->appendCubic(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
|
||||
} else {
|
||||
// if chopMonoCubicAtX failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
} else { // wholly inside the clip
|
||||
this->appendCubic(pts, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
|
||||
SkRect bounds;
|
||||
bounds.set(srcPts, 4);
|
||||
|
||||
if (!quick_reject(bounds, clip)) {
|
||||
SkPoint monoY[10];
|
||||
int countY = SkChopCubicAtYExtrema(srcPts, monoY);
|
||||
for (int y = 0; y <= countY; y++) {
|
||||
// sk_assert_monotonic_y(&monoY[y * 3], 4);
|
||||
SkPoint monoX[10];
|
||||
int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
|
||||
for (int x = 0; x <= countX; x++) {
|
||||
// sk_assert_monotonic_y(&monoX[x * 3], 4);
|
||||
// sk_assert_monotonic_x(&monoX[x * 3], 4);
|
||||
this->clipMonoCubic(&monoX[x * 3], clip);
|
||||
SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
|
||||
SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fCurrVerb = SkPath::kDone_Verb;
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
return SkPath::kDone_Verb != fVerbs[0];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
|
||||
bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kLine_Verb;
|
||||
|
||||
if (reverse) {
|
||||
SkTSwap<SkScalar>(y0, y1);
|
||||
}
|
||||
fCurrPoint[0].set(x, y0);
|
||||
fCurrPoint[1].set(x, y1);
|
||||
fCurrPoint += 2;
|
||||
}
|
||||
|
||||
void SkEdgeClipper::appendQuad(const SkPoint pts[3], bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kQuad_Verb;
|
||||
|
||||
if (reverse) {
|
||||
fCurrPoint[0] = pts[2];
|
||||
fCurrPoint[2] = pts[0];
|
||||
} else {
|
||||
fCurrPoint[0] = pts[0];
|
||||
fCurrPoint[2] = pts[2];
|
||||
}
|
||||
fCurrPoint[1] = pts[1];
|
||||
fCurrPoint += 3;
|
||||
}
|
||||
|
||||
void SkEdgeClipper::appendCubic(const SkPoint pts[4], bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kCubic_Verb;
|
||||
|
||||
if (reverse) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fCurrPoint[i] = pts[3 - i];
|
||||
}
|
||||
} else {
|
||||
memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
|
||||
}
|
||||
fCurrPoint += 4;
|
||||
}
|
||||
|
||||
SkPath::Verb SkEdgeClipper::next(SkPoint pts[]) {
|
||||
SkPath::Verb verb = *fCurrVerb;
|
||||
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
|
||||
fCurrPoint += 2;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
|
||||
fCurrPoint += 3;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
|
||||
fCurrPoint += 4;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kDone_Verb:
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"unexpected verb in quadclippper2 iter");
|
||||
break;
|
||||
}
|
||||
return verb;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
static void assert_monotonic(const SkScalar coord[], int count) {
|
||||
if (coord[0] > coord[(count - 1) * 2]) {
|
||||
for (int i = 1; i < count; i++) {
|
||||
SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
|
||||
}
|
||||
} else if (coord[0] < coord[(count - 1) * 2]) {
|
||||
for (int i = 1; i < count; i++) {
|
||||
SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < count; i++) {
|
||||
SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sk_assert_monotonic_y(const SkPoint pts[], int count) {
|
||||
if (count > 1) {
|
||||
assert_monotonic(&pts[0].fY, count);
|
||||
}
|
||||
}
|
||||
|
||||
void sk_assert_monotonic_x(const SkPoint pts[], int count) {
|
||||
if (count > 1) {
|
||||
assert_monotonic(&pts[0].fX, count);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -17,10 +17,6 @@
|
||||
#include "SkQuadClipper.h"
|
||||
#include "SkGeometry.h"
|
||||
|
||||
static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
|
||||
return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
|
||||
}
|
||||
|
||||
static inline void clamp_le(SkScalar& value, SkScalar max) {
|
||||
if (value > max) {
|
||||
value = max;
|
||||
@ -33,23 +29,6 @@ static inline void clamp_ge(SkScalar& value, SkScalar min) {
|
||||
}
|
||||
}
|
||||
|
||||
/* src[] must be monotonic in Y. This routine copies src into dst, and sorts
|
||||
it to be increasing in Y. If it had to reverse the order of the points,
|
||||
it returns true, otherwise it returns false
|
||||
*/
|
||||
static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
|
||||
// we need the data to be monotonically increasing in Y
|
||||
if (src[0].fY > src[count - 1].fY) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
dst[i] = src[count - i - 1];
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
memcpy(dst, src, count * sizeof(SkPoint));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SkQuadClipper::SkQuadClipper() {}
|
||||
|
||||
void SkQuadClipper::setClip(const SkIRect& clip) {
|
||||
@ -82,409 +61,8 @@ static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
|
||||
return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
|
||||
}
|
||||
|
||||
static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
|
||||
return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
|
||||
}
|
||||
|
||||
// Modify pts[] in place so that it is clipped in Y to the clip rect
|
||||
static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
|
||||
SkScalar t;
|
||||
SkPoint tmp[5]; // for SkChopQuadAt
|
||||
|
||||
// are we partially above
|
||||
if (pts[0].fY < clip.fTop) {
|
||||
if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
|
||||
// take the 2nd chopped quad
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
clamp_ge(tmp[2].fY, clip.fTop);
|
||||
clamp_ge(tmp[3].fY, clip.fTop);
|
||||
pts[0] = tmp[2];
|
||||
pts[1] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the top
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pts[i].fY < clip.fTop) {
|
||||
pts[i].fY = clip.fTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially below
|
||||
if (pts[2].fY > clip.fBottom) {
|
||||
if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fY, clip.fBottom);
|
||||
clamp_le(tmp[2].fY, clip.fBottom);
|
||||
pts[1] = tmp[1];
|
||||
pts[2] = tmp[2];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the bottom
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pts[i].fY > clip.fBottom) {
|
||||
pts[i].fY = clip.fBottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// srcPts[] must be monotonic in X and Y
|
||||
void SkQuadClipper2::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
SkPoint pts[3];
|
||||
bool reverse = sort_increasing_Y(pts, srcPts, 3);
|
||||
|
||||
// are we completely above or below
|
||||
if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now chop so that pts is contained within clip in Y
|
||||
chop_quad_in_Y(pts, clip);
|
||||
|
||||
if (pts[0].fX > pts[2].fX) {
|
||||
SkTSwap<SkPoint>(pts[0], pts[2]);
|
||||
reverse = !reverse;
|
||||
}
|
||||
SkASSERT(pts[0].fX <= pts[1].fX);
|
||||
SkASSERT(pts[1].fX <= pts[2].fX);
|
||||
|
||||
// Now chop in X has needed, and record the segments
|
||||
|
||||
if (pts[2].fX <= clip.fLeft) { // wholly to the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
|
||||
return;
|
||||
}
|
||||
if (pts[0].fX >= clip.fRight) { // wholly to the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar t;
|
||||
SkPoint tmp[5]; // for SkChopQuadAt
|
||||
|
||||
// are we partially to the left
|
||||
if (pts[0].fX < clip.fLeft) {
|
||||
if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
|
||||
clamp_ge(tmp[2].fX, clip.fLeft);
|
||||
clamp_ge(tmp[3].fX, clip.fLeft);
|
||||
pts[0] = tmp[2];
|
||||
pts[1] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially to the right
|
||||
if (pts[2].fX > clip.fRight) {
|
||||
if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fX, clip.fRight);
|
||||
clamp_le(tmp[2].fX, clip.fRight);
|
||||
this->appendQuad(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
} else { // wholly inside the clip
|
||||
this->appendQuad(pts, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkQuadClipper2::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
|
||||
SkRect bounds;
|
||||
bounds.set(srcPts, 3);
|
||||
|
||||
if (!quick_reject(bounds, clip)) {
|
||||
SkPoint monoY[5];
|
||||
int countY = SkChopQuadAtYExtrema(srcPts, monoY);
|
||||
for (int y = 0; y <= countY; y++) {
|
||||
SkPoint monoX[5];
|
||||
int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
|
||||
for (int x = 0; x <= countX; x++) {
|
||||
this->clipMonoQuad(&monoX[x * 2], clip);
|
||||
SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
|
||||
SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fCurrVerb = SkPath::kDone_Verb;
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
return SkPath::kDone_Verb != fVerbs[0];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
|
||||
SkScalar D, SkScalar t) {
|
||||
return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
|
||||
}
|
||||
|
||||
/* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
|
||||
t value such that cubic(t) = target
|
||||
*/
|
||||
static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
|
||||
SkScalar target, SkScalar* t) {
|
||||
// SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
|
||||
SkASSERT(c0 < target && target < c3);
|
||||
|
||||
SkScalar D = c0;
|
||||
SkScalar A = c3 + 3*(c1 - c2) - c0;
|
||||
SkScalar B = 3*(c2 - c1 - c1 + c0);
|
||||
SkScalar C = 3*(c1 - c0);
|
||||
|
||||
SkScalar minT = 0;
|
||||
SkScalar maxT = SK_Scalar1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
SkScalar mid = SkScalarAve(minT, maxT);
|
||||
SkScalar coord = eval_cubic_coeff(A, B, C, D, mid);
|
||||
if (coord < target) {
|
||||
minT = mid;
|
||||
} else {
|
||||
maxT = mid;
|
||||
}
|
||||
}
|
||||
*t = SkScalarAve(minT, maxT);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) {
|
||||
return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t);
|
||||
}
|
||||
|
||||
static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
|
||||
return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t);
|
||||
}
|
||||
|
||||
// Modify pts[] in place so that it is clipped in Y to the clip rect
|
||||
static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
|
||||
SkScalar t;
|
||||
SkPoint tmp[7]; // for SkChopCubicAt
|
||||
|
||||
// are we partially above
|
||||
if (pts[0].fY < clip.fTop) {
|
||||
if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
clamp_ge(tmp[3].fY, clip.fTop);
|
||||
clamp_ge(tmp[4].fY, clip.fTop);
|
||||
clamp_ge(tmp[5].fY, clip.fTop);
|
||||
pts[0] = tmp[3];
|
||||
pts[1] = tmp[4];
|
||||
pts[2] = tmp[5];
|
||||
} else {
|
||||
// if chopMonoCubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the top
|
||||
for (int i = 0; i < 4; i++) {
|
||||
clamp_ge(pts[i].fY, clip.fTop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially below
|
||||
if (pts[3].fY > clip.fBottom) {
|
||||
if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fY, clip.fBottom);
|
||||
clamp_le(tmp[2].fY, clip.fBottom);
|
||||
clamp_le(tmp[3].fY, clip.fBottom);
|
||||
pts[1] = tmp[1];
|
||||
pts[2] = tmp[2];
|
||||
pts[3] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoCubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the bottom
|
||||
for (int i = 0; i < 4; i++) {
|
||||
clamp_le(pts[i].fY, clip.fBottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// srcPts[] must be monotonic in X and Y
|
||||
void SkQuadClipper2::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
|
||||
SkPoint pts[4];
|
||||
bool reverse = sort_increasing_Y(pts, src, 4);
|
||||
|
||||
// are we completely above or below
|
||||
if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now chop so that pts is contained within clip in Y
|
||||
chop_cubic_in_Y(pts, clip);
|
||||
|
||||
if (pts[0].fX > pts[3].fX) {
|
||||
SkTSwap<SkPoint>(pts[0], pts[3]);
|
||||
SkTSwap<SkPoint>(pts[1], pts[2]);
|
||||
reverse = !reverse;
|
||||
}
|
||||
|
||||
// Now chop in X has needed, and record the segments
|
||||
|
||||
if (pts[3].fX <= clip.fLeft) { // wholly to the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
|
||||
return;
|
||||
}
|
||||
if (pts[0].fX >= clip.fRight) { // wholly to the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar t;
|
||||
SkPoint tmp[7];
|
||||
|
||||
// are we partially to the left
|
||||
if (pts[0].fX < clip.fLeft) {
|
||||
if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
|
||||
clamp_ge(tmp[3].fX, clip.fLeft);
|
||||
clamp_ge(tmp[4].fX, clip.fLeft);
|
||||
clamp_ge(tmp[5].fX, clip.fLeft);
|
||||
pts[0] = tmp[3];
|
||||
pts[1] = tmp[4];
|
||||
pts[2] = tmp[5];
|
||||
} else {
|
||||
// if chopMonocubicAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially to the right
|
||||
if (pts[3].fX > clip.fRight) {
|
||||
if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
|
||||
SkChopCubicAt(pts, tmp, t);
|
||||
clamp_le(tmp[1].fX, clip.fRight);
|
||||
clamp_le(tmp[2].fX, clip.fRight);
|
||||
clamp_le(tmp[3].fX, clip.fRight);
|
||||
this->appendCubic(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
|
||||
} else {
|
||||
// if chopMonoCubicAtX failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
} else { // wholly inside the clip
|
||||
this->appendCubic(pts, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkQuadClipper2::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
|
||||
SkRect bounds;
|
||||
bounds.set(srcPts, 4);
|
||||
|
||||
if (!quick_reject(bounds, clip)) {
|
||||
SkPoint monoY[10];
|
||||
int countY = SkChopCubicAtYExtrema(srcPts, monoY);
|
||||
for (int y = 0; y <= countY; y++) {
|
||||
// sk_assert_monotonic_y(&monoY[y * 3], 4);
|
||||
SkPoint monoX[10];
|
||||
int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
|
||||
for (int x = 0; x <= countX; x++) {
|
||||
// sk_assert_monotonic_y(&monoX[x * 3], 4);
|
||||
// sk_assert_monotonic_x(&monoX[x * 3], 4);
|
||||
this->clipMonoCubic(&monoX[x * 3], clip);
|
||||
SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
|
||||
SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fCurrVerb = SkPath::kDone_Verb;
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
return SkPath::kDone_Verb != fVerbs[0];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkQuadClipper2::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
|
||||
bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kLine_Verb;
|
||||
|
||||
if (reverse) {
|
||||
SkTSwap<SkScalar>(y0, y1);
|
||||
}
|
||||
fCurrPoint[0].set(x, y0);
|
||||
fCurrPoint[1].set(x, y1);
|
||||
fCurrPoint += 2;
|
||||
}
|
||||
|
||||
void SkQuadClipper2::appendQuad(const SkPoint pts[3], bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kQuad_Verb;
|
||||
|
||||
if (reverse) {
|
||||
fCurrPoint[0] = pts[2];
|
||||
fCurrPoint[2] = pts[0];
|
||||
} else {
|
||||
fCurrPoint[0] = pts[0];
|
||||
fCurrPoint[2] = pts[2];
|
||||
}
|
||||
fCurrPoint[1] = pts[1];
|
||||
fCurrPoint += 3;
|
||||
}
|
||||
|
||||
void SkQuadClipper2::appendCubic(const SkPoint pts[4], bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kCubic_Verb;
|
||||
|
||||
if (reverse) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fCurrPoint[i] = pts[3 - i];
|
||||
}
|
||||
} else {
|
||||
memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
|
||||
}
|
||||
fCurrPoint += 4;
|
||||
}
|
||||
|
||||
SkPath::Verb SkQuadClipper2::next(SkPoint pts[]) {
|
||||
SkPath::Verb verb = *fCurrVerb;
|
||||
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
|
||||
fCurrPoint += 2;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
|
||||
fCurrPoint += 3;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
|
||||
fCurrPoint += 4;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kDone_Verb:
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"unexpected verb in quadclippper2 iter");
|
||||
break;
|
||||
}
|
||||
return verb;
|
||||
}
|
||||
|
||||
//////////
|
||||
//////////
|
||||
|
||||
/* If we somehow returned the fact that we had to flip the pts in Y, we could
|
||||
communicate that to setQuadratic, and then avoid having to flip it back
|
||||
here (only to have setQuadratic do the flip again)
|
||||
@ -554,34 +132,3 @@ bool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
static void assert_monotonic(const SkScalar coord[], int count) {
|
||||
if (coord[0] > coord[(count - 1) * 2]) {
|
||||
for (int i = 1; i < count; i++) {
|
||||
SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
|
||||
}
|
||||
} else if (coord[0] < coord[(count - 1) * 2]) {
|
||||
for (int i = 1; i < count; i++) {
|
||||
SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < count; i++) {
|
||||
SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sk_assert_monotonic_y(const SkPoint pts[], int count) {
|
||||
if (count > 1) {
|
||||
assert_monotonic(&pts[0].fY, count);
|
||||
}
|
||||
}
|
||||
|
||||
void sk_assert_monotonic_x(const SkPoint pts[], int count) {
|
||||
if (count > 1) {
|
||||
assert_monotonic(&pts[0].fX, count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "SkRegion.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
//#define USE_NEW_BUILDER
|
||||
|
||||
#define kEDGE_HEAD_Y SK_MinS32
|
||||
#define kEDGE_TAIL_Y SK_MaxS32
|
||||
|
||||
@ -301,6 +303,9 @@ static inline bool line_too_big(const SkPoint pts[2])
|
||||
SkScalarAbs(dy) > SkIntToScalar(511);
|
||||
}
|
||||
|
||||
#ifdef USE_NEW_BUILDER
|
||||
#include "SkEdgeBuilder.h"
|
||||
#else
|
||||
static int build_edges(SkEdge edge[], const SkPath& path,
|
||||
const SkIRect* clipRect, SkEdge* list[], int shiftUp) {
|
||||
SkEdge** start = list;
|
||||
@ -428,6 +433,7 @@ static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) {
|
||||
*storage = quadSize;
|
||||
return edgeCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -474,6 +480,12 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
|
||||
{
|
||||
SkASSERT(&path && blitter);
|
||||
|
||||
#ifdef USE_NEW_BUILDER
|
||||
SkEdgeBuilder builder;
|
||||
|
||||
int count = builder.build(path, clipRect, shiftEdgesUp);
|
||||
SkEdge** list = builder.edgeList();
|
||||
#else
|
||||
size_t size;
|
||||
int maxCount = cheap_worst_case_edge_count(path, &size);
|
||||
|
||||
@ -488,17 +500,19 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
|
||||
|
||||
SkAutoMalloc memory(maxCount * sizeof(SkEdge*) + size);
|
||||
SkEdge** list = (SkEdge**)memory.get();
|
||||
SkEdge* edge = (SkEdge*)(list + maxCount);
|
||||
int count = build_edges(edge, path, clipRect, list, shiftEdgesUp);
|
||||
SkEdge headEdge, tailEdge, *last;
|
||||
|
||||
SkEdge* initialEdge = (SkEdge*)(list + maxCount);
|
||||
int count = build_edges(initialEdge, path, clipRect, list,
|
||||
shiftEdgesUp);
|
||||
SkASSERT(count <= maxCount);
|
||||
#endif
|
||||
|
||||
if (count < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkEdge headEdge, tailEdge, *last;
|
||||
// this returns the first and last edge after they're sorted into a dlink list
|
||||
edge = sort_edges(list, count, &last);
|
||||
SkEdge* edge = sort_edges(list, count, &last);
|
||||
|
||||
headEdge.fPrev = NULL;
|
||||
headEdge.fNext = edge;
|
||||
|
@ -34,6 +34,8 @@ SOURCE := \
|
||||
SkDither.cpp \
|
||||
SkDraw.cpp \
|
||||
SkEdge.cpp \
|
||||
SkEdgeBuilder.cpp \
|
||||
SkEdgeClipper.cpp \
|
||||
SkFilterProc.cpp \
|
||||
SkFlattenable.cpp \
|
||||
SkFloat.cpp \
|
||||
@ -43,6 +45,7 @@ SOURCE := \
|
||||
SkGlobals.cpp \
|
||||
SkGlyphCache.cpp \
|
||||
SkGraphics.cpp \
|
||||
SkLineClipper.cpp \
|
||||
SkMMapStream.cpp \
|
||||
SkMask.cpp \
|
||||
SkMaskFilter.cpp \
|
||||
|
@ -33,7 +33,6 @@
|
||||
005F25820EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F25090EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h */; };
|
||||
005F25830EF94F7900582A90 /* SkBitmapShaderTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F250A0EF94F7900582A90 /* SkBitmapShaderTemplate.h */; };
|
||||
005F25840EF94F7900582A90 /* SkBlitBWMaskTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F250B0EF94F7900582A90 /* SkBlitBWMaskTemplate.h */; };
|
||||
005F25850EF94F7900582A90 /* SkBlitRow.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F250C0EF94F7900582A90 /* SkBlitRow.h */; };
|
||||
005F25860EF94F7900582A90 /* SkBlitRow_D16.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F250D0EF94F7900582A90 /* SkBlitRow_D16.cpp */; };
|
||||
005F25870EF94F7900582A90 /* SkBlitRow_D4444.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F250E0EF94F7900582A90 /* SkBlitRow_D4444.cpp */; };
|
||||
005F25880EF94F7900582A90 /* SkBlitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F250F0EF94F7900582A90 /* SkBlitter.cpp */; };
|
||||
@ -129,7 +128,9 @@
|
||||
005F26960EF955D400582A90 /* SkComposeShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F26950EF955D400582A90 /* SkComposeShader.cpp */; };
|
||||
007C786A0F3B4D5F0004B142 /* SkQuadClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007C78690F3B4D5F0004B142 /* SkQuadClipper.cpp */; };
|
||||
0096586E0FC7205100C3AE15 /* SkShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0096586D0FC7205100C3AE15 /* SkShape.cpp */; };
|
||||
009CC7920F5DAF4B002185BE /* SkCubicClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009CC7910F5DAF4B002185BE /* SkCubicClipper.cpp */; };
|
||||
00F043FC10B445F50049C54C /* SkEdgeBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00F043F910B445F50049C54C /* SkEdgeBuilder.cpp */; };
|
||||
00F043FD10B445F50049C54C /* SkEdgeClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00F043FA10B445F50049C54C /* SkEdgeClipper.cpp */; };
|
||||
00F043FE10B445F50049C54C /* SkLineClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00F043FB10B445F50049C54C /* SkLineClipper.cpp */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -159,7 +160,6 @@
|
||||
005F25090EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBitmapShader16BilerpTemplate.h; path = ../../src/core/SkBitmapShader16BilerpTemplate.h; sourceTree = SOURCE_ROOT; };
|
||||
005F250A0EF94F7900582A90 /* SkBitmapShaderTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBitmapShaderTemplate.h; path = ../../src/core/SkBitmapShaderTemplate.h; sourceTree = SOURCE_ROOT; };
|
||||
005F250B0EF94F7900582A90 /* SkBlitBWMaskTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBlitBWMaskTemplate.h; path = ../../src/core/SkBlitBWMaskTemplate.h; sourceTree = SOURCE_ROOT; };
|
||||
005F250C0EF94F7900582A90 /* SkBlitRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBlitRow.h; path = ../../src/core/SkBlitRow.h; sourceTree = SOURCE_ROOT; };
|
||||
005F250D0EF94F7900582A90 /* SkBlitRow_D16.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkBlitRow_D16.cpp; path = ../../src/core/SkBlitRow_D16.cpp; sourceTree = SOURCE_ROOT; };
|
||||
005F250E0EF94F7900582A90 /* SkBlitRow_D4444.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkBlitRow_D4444.cpp; path = ../../src/core/SkBlitRow_D4444.cpp; sourceTree = SOURCE_ROOT; };
|
||||
005F250F0EF94F7900582A90 /* SkBlitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkBlitter.cpp; path = ../../src/core/SkBlitter.cpp; sourceTree = SOURCE_ROOT; };
|
||||
@ -255,7 +255,9 @@
|
||||
005F26950EF955D400582A90 /* SkComposeShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkComposeShader.cpp; path = ../../src/core/SkComposeShader.cpp; sourceTree = SOURCE_ROOT; };
|
||||
007C78690F3B4D5F0004B142 /* SkQuadClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkQuadClipper.cpp; path = ../../src/core/SkQuadClipper.cpp; sourceTree = SOURCE_ROOT; };
|
||||
0096586D0FC7205100C3AE15 /* SkShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkShape.cpp; path = ../../src/core/SkShape.cpp; sourceTree = SOURCE_ROOT; };
|
||||
009CC7910F5DAF4B002185BE /* SkCubicClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkCubicClipper.cpp; path = ../../src/core/SkCubicClipper.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00F043F910B445F50049C54C /* SkEdgeBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkEdgeBuilder.cpp; path = ../../src/core/SkEdgeBuilder.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00F043FA10B445F50049C54C /* SkEdgeClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkEdgeClipper.cpp; path = ../../src/core/SkEdgeClipper.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00F043FB10B445F50049C54C /* SkLineClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkLineClipper.cpp; path = ../../src/core/SkLineClipper.cpp; sourceTree = SOURCE_ROOT; };
|
||||
D2AAC046055464E500DB518D /* libcore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcore.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -300,12 +302,14 @@
|
||||
08FB7795FE84155DC02AAC07 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
00F043F910B445F50049C54C /* SkEdgeBuilder.cpp */,
|
||||
00F043FA10B445F50049C54C /* SkEdgeClipper.cpp */,
|
||||
00F043FB10B445F50049C54C /* SkLineClipper.cpp */,
|
||||
00244E0F106A6DEA00B8F4D8 /* SkBlitRow_D32.cpp */,
|
||||
00554E0C102733D300C9C8ED /* SkBitmapProcState_opts_none.cpp */,
|
||||
002B342710213340000F04C6 /* SkBlitRow_opts_none.cpp */,
|
||||
005DC79A10179AE000F00DFB /* SkFontHost.cpp */,
|
||||
005DC79810179ACD00F00DFB /* SkBlitter_ARGB32_Subpixel.cpp */,
|
||||
009CC7910F5DAF4B002185BE /* SkCubicClipper.cpp */,
|
||||
007C78690F3B4D5F0004B142 /* SkQuadClipper.cpp */,
|
||||
002884D40EFAB8F80083E387 /* SkStream.cpp */,
|
||||
002884C70EFAB8B90083E387 /* SkMMapStream.cpp */,
|
||||
@ -329,7 +333,6 @@
|
||||
005F25090EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h */,
|
||||
005F250A0EF94F7900582A90 /* SkBitmapShaderTemplate.h */,
|
||||
005F250B0EF94F7900582A90 /* SkBlitBWMaskTemplate.h */,
|
||||
005F250C0EF94F7900582A90 /* SkBlitRow.h */,
|
||||
005F250D0EF94F7900582A90 /* SkBlitRow_D16.cpp */,
|
||||
005F250E0EF94F7900582A90 /* SkBlitRow_D4444.cpp */,
|
||||
005F250F0EF94F7900582A90 /* SkBlitter.cpp */,
|
||||
@ -459,7 +462,6 @@
|
||||
005F25820EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h in Headers */,
|
||||
005F25830EF94F7900582A90 /* SkBitmapShaderTemplate.h in Headers */,
|
||||
005F25840EF94F7900582A90 /* SkBlitBWMaskTemplate.h in Headers */,
|
||||
005F25850EF94F7900582A90 /* SkBlitRow.h in Headers */,
|
||||
005F25970EF94F7900582A90 /* SkCordic.h in Headers */,
|
||||
005F25980EF94F7900582A90 /* SkCoreBlitters.h in Headers */,
|
||||
005F259F0EF94F7900582A90 /* SkDrawProcs.h in Headers */,
|
||||
@ -609,13 +611,15 @@
|
||||
002884C80EFAB8B90083E387 /* SkMMapStream.cpp in Sources */,
|
||||
002884D50EFAB8F80083E387 /* SkStream.cpp in Sources */,
|
||||
007C786A0F3B4D5F0004B142 /* SkQuadClipper.cpp in Sources */,
|
||||
009CC7920F5DAF4B002185BE /* SkCubicClipper.cpp in Sources */,
|
||||
0096586E0FC7205100C3AE15 /* SkShape.cpp in Sources */,
|
||||
005DC79910179ACD00F00DFB /* SkBlitter_ARGB32_Subpixel.cpp in Sources */,
|
||||
005DC79B10179AE000F00DFB /* SkFontHost.cpp in Sources */,
|
||||
002B342810213340000F04C6 /* SkBlitRow_opts_none.cpp in Sources */,
|
||||
00554E0D102733D300C9C8ED /* SkBitmapProcState_opts_none.cpp in Sources */,
|
||||
00244E10106A6DEA00B8F4D8 /* SkBlitRow_D32.cpp in Sources */,
|
||||
00F043FC10B445F50049C54C /* SkEdgeBuilder.cpp in Sources */,
|
||||
00F043FD10B445F50049C54C /* SkEdgeClipper.cpp in Sources */,
|
||||
00F043FE10B445F50049C54C /* SkLineClipper.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user