**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp,
const SkRegion& clipRgn);
-// blit the rects above and below avoid, clipped to clp
-void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& avoid,
- const SkRegion& clip);
+// blit the rects above and below avoid, clipped to clip
+void sk_blit_above(SkBlitter*, const SkIRect& avoid, const SkRegion& clip);
+void sk_blit_below(SkBlitter*, const SkIRect& avoid, const SkRegion& clip);
#endif
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip) {
fRealBlitter = realBlitter;
-
+
// take the union of the ir bounds and clip, since we may be called with an
// inverse filltype
const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft);
const int right = SkMax32(ir.fRight, clip.getBounds().fRight);
-
+
fLeft = left;
fSuperLeft = left << SHIFT;
fWidth = right - left;
// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
#if 0
- SkAntiRun<SHIFT> arun;
+ SkAntiRun<SHIFT> arun;
arun.set(x, x + width);
fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue);
#else
{
int width = bounds.width();
int rb = SkAlign4(width);
-
+
return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
(rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE);
}
-
+
private:
enum {
kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
fMask.fBounds = ir;
fMask.fRowBytes = ir.width();
fMask.fFormat = SkMask::kA8_Format;
-
+
fClipRect = ir;
fClipRect.intersect(clip.getBounds());
-
+
// For valgrind, write 1 extra byte at the end so we don't read
// uninitialized memory. See comment in add_aa_span and fStorage[].
memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
void MaskSuperBlitter::blitH(int x, int y, int width)
{
int iy = (y >> SHIFT);
-
+
SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
iy -= fMask.fBounds.fTop; // make it relative to 0
SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
}
#endif
-
+
x -= (fMask.fBounds.fLeft << SHIFT);
// hack, until I figure out why my cubics (I think) go beyond the bounds
}
return;
}
-
+
// now use the (possibly wrapped) blitter
blitter = clipper.getBlitter();
if (path.isInverseFillType()) {
- sk_blit_above_and_below(blitter, ir, clip);
+ sk_blit_above(blitter, ir, clip);
}
SkIRect superRect, *superClipRect = NULL;
SuperBlitter superBlit(blitter, ir, clip);
sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
}
+
+ if (path.isInverseFillType()) {
+ sk_blit_below(blitter, ir, clip);
+ }
}
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
for (;;)
{
SkEdge* prev = edge->fPrev;
-
+
// add 1 to curr_y since we may have added new edges (built from curves)
// that start on the next scanline
SkASSERT(prev && prev->fFirstY <= curr_y + 1);
SkFixed prevX = prevHead->fX;
validate_edges_for_y(currE, curr_y);
-
+
if (proc) {
proc(blitter, curr_y, PREPOST_START); // pre-proc
}
-
+
while (currE->fFirstY <= curr_y)
{
SkASSERT(currE->fLastY >= curr_y);
if (((SkCubicEdge*)currE)->updateCubic())
{
SkASSERT(currE->fFirstY == curr_y + 1);
-
+
newX = currE->fX;
goto NEXT_X;
}
currE = next;
SkASSERT(currE);
}
-
+
if (proc) {
proc(blitter, curr_y, PREPOST_END); // post-proc
}
}
fPrevX = x + width;
}
-
+
// we do not expect to get called with these entrypoints
virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) {
SkASSERT(!"blitAntiH unexpected");
SkASSERT(!"justAnOpaqueColor unexpected");
return NULL;
}
-
+
private:
SkBlitter* fBlitter;
int fFirstX, fLastX, fPrevX;
SkPath::Iter iter(path, true);
SkPoint pts[4];
SkPath::Verb verb;
-
+
SkQuadClipper qclipper;
if (clipRect) {
SkIRect r;
case SkPath::kCubic_Verb: {
SkPoint tmp[10];
SkPoint* p = tmp;
- int count = SkChopCubicAtYExtrema(pts, tmp);
+ int count = SkChopCubicAtYExtrema(pts, tmp);
SkASSERT(count >= 0 && count <= 2);
do {
*/
static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) {
int ptCount = path.getPoints(NULL, 0);
- // worst case is curve, close, curve, close, as that is
+ // worst case is curve, close, curve, close, as that is
// 2 lines per pt, or : pts * 2
// 2 quads + 1 line per 2 pts, or : pts * 3 / 2
// 3 cubics + 1 line per 3 pts : pts * 4 / 3
static int edge_compare(const void* a, const void* b) {
const SkEdge* edgea = *(const SkEdge**)a;
const SkEdge* edgeb = *(const SkEdge**)b;
-
+
int valuea = edgea->fFirstY;
int valueb = edgeb->fFirstY;
-
+
if (valuea == valueb) {
valuea = edgea->fX;
valueb = edgeb->fX;
}
-
+
// this overflows if valuea >>> valueb or vice-versa
// return valuea - valueb;
// do perform the slower but safe compares
static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
qsort(list, count, sizeof(SkEdge*), edge_compare);
-
+
// now make the edges linked in sorted order
for (int i = 1; i < count; i++) {
list[i - 1]->fNext = list[i];
list[i]->fPrev = list[i - 1];
}
-
+
*last = list[count - 1];
return list[0];
}
#ifdef USE_NEW_BUILDER
SkEdgeBuilder builder;
-
+
int count = builder.build(path, clipRect, shiftEdgesUp);
SkEdge** list = builder.edgeList();
#else
{
size_t size2;
int maxCount2 = worst_case_edge_count(path, &size2);
-
+
SkASSERT(maxCount >= maxCount2 && size >= size2);
}
#endif
walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc);
}
-void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& ir,
- const SkRegion& clip) {
+void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
const SkIRect& cr = clip.getBounds();
SkIRect tmp;
-
+
tmp.fLeft = cr.fLeft;
tmp.fRight = cr.fRight;
-
tmp.fTop = cr.fTop;
tmp.fBottom = ir.fTop;
if (!tmp.isEmpty()) {
blitter->blitRectRegion(tmp, clip);
}
+}
+
+void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
+ const SkIRect& cr = clip.getBounds();
+ SkIRect tmp;
+ tmp.fLeft = cr.fLeft;
+ tmp.fRight = cr.fRight;
tmp.fTop = ir.fBottom;
tmp.fBottom = cr.fBottom;
if (!tmp.isEmpty()) {
blitter = clipper.getBlitter();
if (blitter) {
+ // we have to keep our calls to blitter in sorted order, so we
+ // must blit the above section first, then the middle, then the bottom.
if (path.isInverseFillType()) {
- sk_blit_above_and_below(blitter, ir, clip);
+ sk_blit_above(blitter, ir, clip);
}
sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, 0, clip);
+ if (path.isInverseFillType()) {
+ sk_blit_below(blitter, ir, clip);
+ }
} else {
// what does it mean to not have a blitter if path.isInverseFillType???
}
static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
const SkIRect* clipRect, SkEdge* list[]) {
SkEdge** start = list;
-
+
if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
*list++ = edge;
edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
SkBlitter* blitter, const SkIRect& ir) {
SkASSERT(pts && blitter);
-
+
SkEdge edgeStorage[3];
SkEdge* list[3];
// this returns the first and last edge after they're sorted into a dlink list
SkEdge* edge = sort_edges(list, count, &last);
-
+
headEdge.fPrev = NULL;
headEdge.fNext = edge;
headEdge.fFirstY = kEDGE_HEAD_Y;
headEdge.fX = SK_MinS32;
edge->fPrev = &headEdge;
-
+
tailEdge.fPrev = last;
tailEdge.fNext = NULL;
tailEdge.fFirstY = kEDGE_TAIL_Y;
last->fNext = &tailEdge;
-
+
// now edge is the head of the sorted linklist
int stop_y = ir.fBottom;
if (clipRect && stop_y > clipRect->fBottom) {
if (clip && clip->isEmpty()) {
return;
}
-
+
SkRect r;
SkIRect ir;
r.set(pts, 3);
if (ir.isEmpty()) {
return;
}
-
+
SkScanClipper clipper(blitter, clip, ir);
-
+
blitter = clipper.getBlitter();
if (NULL != blitter) {
sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);