faster stroke rects
git-svn-id: http://skia.googlecode.com/svn/trunk@1042 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
f687087633
commit
7ff678bc16
@ -1,6 +1,6 @@
|
||||
/* libs/graphics/sgl/SkScan.h
|
||||
**
|
||||
** Copyright 2006, The Android Open Source Project
|
||||
** Copyright 2011, 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.
|
||||
@ -42,10 +42,9 @@ public:
|
||||
#else
|
||||
static void FillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
|
||||
#endif
|
||||
|
||||
static void FillTriangle(const SkPoint pts[], const SkRegion*, SkBlitter*);
|
||||
static void FillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
|
||||
|
||||
static void FillTriangle(const SkPoint pts[], const SkRegion*, SkBlitter*);
|
||||
static void FillTriangle(const SkPoint& a, const SkPoint& b,
|
||||
const SkPoint& c, const SkRegion* clip,
|
||||
SkBlitter* blitter) {
|
||||
@ -56,12 +55,11 @@ public:
|
||||
FillTriangle(pts, clip, blitter);
|
||||
}
|
||||
|
||||
static void HairLine(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*);
|
||||
static void HairLine(const SkPoint&, const SkPoint&, const SkRegion*,
|
||||
SkBlitter*);
|
||||
static void HairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
|
||||
static void HairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
|
||||
|
||||
static void FrameRect(const SkRect&, SkScalar width, const SkRegion* clip, SkBlitter*);
|
||||
|
||||
static void AntiFillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
|
||||
#ifdef SK_SCALAR_IS_FIXED
|
||||
static void AntiFillRect(const SkRect& rect, const SkRegion* clip,
|
||||
@ -74,9 +72,16 @@ public:
|
||||
|
||||
static void AntiFillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
|
||||
|
||||
static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*);
|
||||
static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRegion*,
|
||||
SkBlitter*);
|
||||
static void AntiHairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
|
||||
static void AntiHairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
|
||||
|
||||
// draws with a miter-join
|
||||
static void FrameRect(const SkRect&, SkScalar width, const SkRegion*,
|
||||
SkBlitter*);
|
||||
static void AntiFrameRect(const SkRect&, SkScalar width, const SkRegion*,
|
||||
SkBlitter*);
|
||||
};
|
||||
|
||||
/** Assign an SkXRect from a SkIRect, by promoting the src rect's coordinates
|
||||
|
@ -679,6 +679,18 @@ static inline SkPoint* as_rightbottom(SkRect* r) {
|
||||
return ((SkPoint*)(void*)r) + 1;
|
||||
}
|
||||
|
||||
static bool easy_rect_join(const SkPaint& paint) {
|
||||
return SkPaint::kMiter_Join == paint.getStrokeJoin() &&
|
||||
paint.getStrokeMiter() >= SK_ScalarSqrt2;
|
||||
}
|
||||
|
||||
enum RectType {
|
||||
kHair_RectType,
|
||||
kFill_RectType,
|
||||
kStroke_RectType,
|
||||
kPath_RectType
|
||||
};
|
||||
|
||||
void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
||||
@ -688,11 +700,30 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
|
||||
return;
|
||||
}
|
||||
|
||||
// complex enough to draw as a path
|
||||
RectType rtype;
|
||||
const SkScalar width = paint.getStrokeWidth();
|
||||
bool zeroWidth = (0 == width);
|
||||
SkPaint::Style style = paint.getStyle();
|
||||
|
||||
if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
|
||||
style = SkPaint::kFill_Style;
|
||||
}
|
||||
|
||||
if (paint.getPathEffect() || paint.getMaskFilter() ||
|
||||
paint.getRasterizer() || !fMatrix->rectStaysRect() ||
|
||||
(paint.getStyle() != SkPaint::kFill_Style &&
|
||||
SkScalarHalf(paint.getStrokeWidth()) > 0)) {
|
||||
paint.getRasterizer() || !fMatrix->rectStaysRect() ||
|
||||
SkPaint::kStrokeAndFill_Style == style) {
|
||||
rtype = kPath_RectType;
|
||||
} else if (SkPaint::kFill_Style == paint.getStyle()) {
|
||||
rtype = kFill_RectType;
|
||||
} else if (zeroWidth) {
|
||||
rtype = kHair_RectType;
|
||||
} else if (easy_rect_join(paint)) {
|
||||
rtype = kStroke_RectType;
|
||||
} else {
|
||||
rtype = kPath_RectType;
|
||||
}
|
||||
|
||||
if (kPath_RectType == rtype) {
|
||||
SkPath tmp;
|
||||
tmp.addRect(rect);
|
||||
tmp.setFillType(SkPath::kWinding_FillType);
|
||||
@ -733,18 +764,30 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
|
||||
// we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
|
||||
// case we are also hairline (if we've gotten to here), which devolves to
|
||||
// effectively just kFill
|
||||
if (paint.getStyle() != SkPaint::kStroke_Style) {
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFillRect(devRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::FillRect(devRect, clip, blitter);
|
||||
}
|
||||
} else {
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiHairRect(devRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::HairRect(devRect, clip, blitter);
|
||||
}
|
||||
switch (rtype) {
|
||||
case kFill_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFillRect(devRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::FillRect(devRect, clip, blitter);
|
||||
}
|
||||
break;
|
||||
case kStroke_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFrameRect(devRect, width, clip, blitter);
|
||||
} else {
|
||||
SkScan::FrameRect(devRect, width, clip, blitter);
|
||||
}
|
||||
break;
|
||||
case kHair_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiHairRect(devRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::HairRect(devRect, clip, blitter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"bad rtype");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* libs/graphics/sgl/SkScan_Antihair.cpp
|
||||
**
|
||||
** Copyright 2006, The Android Open Source Project
|
||||
** Copyright 2011, 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.
|
||||
@ -530,13 +530,8 @@ static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha, SkBlitter* blitt
|
||||
blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
|
||||
}
|
||||
|
||||
static void antifillrect(const SkXRect& xr, SkBlitter* blitter)
|
||||
{
|
||||
FDot8 L = SkFixedToFDot8(xr.fLeft);
|
||||
FDot8 T = SkFixedToFDot8(xr.fTop);
|
||||
FDot8 R = SkFixedToFDot8(xr.fRight);
|
||||
FDot8 B = SkFixedToFDot8(xr.fBottom);
|
||||
|
||||
static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
|
||||
bool fillInner) {
|
||||
// check for empty now that we're in our reduced precision space
|
||||
if (L >= R || T >= B)
|
||||
return;
|
||||
@ -566,7 +561,7 @@ static void antifillrect(const SkXRect& xr, SkBlitter* blitter)
|
||||
}
|
||||
int rite = R >> 8;
|
||||
int width = rite - left;
|
||||
if (width > 0)
|
||||
if (width > 0 && fillInner)
|
||||
blitter->blitRect(left, top, width, height);
|
||||
if (R & 0xFF)
|
||||
blitter->blitV(rite, top, height, R & 0xFF);
|
||||
@ -576,6 +571,12 @@ static void antifillrect(const SkXRect& xr, SkBlitter* blitter)
|
||||
do_scanline(L, bot, R, B & 0xFF, blitter);
|
||||
}
|
||||
|
||||
static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
|
||||
antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
|
||||
SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
|
||||
blitter, true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
|
||||
@ -667,6 +668,159 @@ void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// calls blitRect() if the rectangle is non-empty
|
||||
static void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
|
||||
if (L < R && T < B) {
|
||||
blitter->blitRect(L, T, R - L, B - T);
|
||||
}
|
||||
}
|
||||
|
||||
static inline FDot8 SkScalarToFDot8(SkScalar x) {
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
return (int)(x * 256);
|
||||
#else
|
||||
return x >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int FDot8Floor(FDot8 x) {
|
||||
return x >> 8;
|
||||
}
|
||||
|
||||
static inline int FDot8Ceil(FDot8 x) {
|
||||
return (x + 0xFF) >> 8;
|
||||
}
|
||||
|
||||
// 1 - (1 - a)*(1 - b)
|
||||
static inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
|
||||
return SkToU8(a + b - SkAlphaMul(a, b));
|
||||
}
|
||||
|
||||
static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
|
||||
SkBlitter* blitter) {
|
||||
SkASSERT(L < R);
|
||||
|
||||
if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel
|
||||
blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
|
||||
return;
|
||||
}
|
||||
|
||||
int left = L >> 8;
|
||||
if (L & 0xFF) {
|
||||
blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
|
||||
left += 1;
|
||||
}
|
||||
|
||||
int rite = R >> 8;
|
||||
int width = rite - left;
|
||||
if (width > 0) {
|
||||
call_hline_blitter(blitter, left, top, width, alpha);
|
||||
}
|
||||
|
||||
if (R & 0xFF) {
|
||||
blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
|
||||
SkBlitter* blitter) {
|
||||
SkASSERT(L < R && T < B);
|
||||
|
||||
int top = T >> 8;
|
||||
if (top == ((B - 1) >> 8)) { // just one scanline high
|
||||
inner_scanline(L, top, R, B - T, blitter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (T & 0xFF) {
|
||||
inner_scanline(L, top, R, T & 0xFF, blitter);
|
||||
top += 1;
|
||||
}
|
||||
|
||||
int bot = B >> 8;
|
||||
int height = bot - top;
|
||||
if (height > 0) {
|
||||
if (L & 0xFF) {
|
||||
blitter->blitV(L >> 8, top, height, L & 0xFF);
|
||||
}
|
||||
if (R & 0xFF) {
|
||||
blitter->blitV(R >> 8, top, height, ~R & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
if (B & 0xFF) {
|
||||
inner_scanline(L, bot, R, ~B & 0xFF, blitter);
|
||||
}
|
||||
}
|
||||
|
||||
void SkScan::AntiFrameRect(const SkRect& r, SkScalar diameter,
|
||||
const SkRegion* clip, SkBlitter* blitter) {
|
||||
SkASSERT(diameter > 0);
|
||||
|
||||
SkScalar radius = SkScalarHalf(diameter);
|
||||
|
||||
// outset by the radius
|
||||
FDot8 L = SkScalarToFDot8(r.fLeft - radius);
|
||||
FDot8 T = SkScalarToFDot8(r.fTop - radius);
|
||||
FDot8 R = SkScalarToFDot8(r.fRight + radius);
|
||||
FDot8 B = SkScalarToFDot8(r.fBottom + radius);
|
||||
|
||||
SkIRect outer;
|
||||
// set outer to the outer rect of the outer section
|
||||
outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
|
||||
|
||||
SkBlitterClipper clipper;
|
||||
if (clip) {
|
||||
if (clip->quickReject(outer)) {
|
||||
return;
|
||||
}
|
||||
if (!clip->contains(outer)) {
|
||||
blitter = clipper.apply(blitter, clip, &outer);
|
||||
}
|
||||
// now we can ignore clip for the rest of the function
|
||||
}
|
||||
|
||||
// stroke the outer hull
|
||||
antifilldot8(L, T, R, B, blitter, false);
|
||||
|
||||
// set outer to the outer rect of the middle section
|
||||
outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
|
||||
|
||||
// in case we lost a bit with diameter/2
|
||||
radius = diameter - radius;
|
||||
// inset by the radius
|
||||
L = SkScalarToFDot8(r.fLeft + radius);
|
||||
T = SkScalarToFDot8(r.fTop + radius);
|
||||
R = SkScalarToFDot8(r.fRight - radius);
|
||||
B = SkScalarToFDot8(r.fBottom - radius);
|
||||
|
||||
if (L >= R || T >= B) {
|
||||
fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
|
||||
blitter);
|
||||
} else {
|
||||
SkIRect inner;
|
||||
// set inner to the inner rect of the middle section
|
||||
inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
|
||||
|
||||
// draw the frame in 4 pieces
|
||||
fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
|
||||
blitter);
|
||||
fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
|
||||
blitter);
|
||||
fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
|
||||
blitter);
|
||||
fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
|
||||
blitter);
|
||||
|
||||
// now stroke the inner rect, which is similar to antifilldot8() except that
|
||||
// it treats the fractional coordinates with the inverse bias (since its
|
||||
// inner).
|
||||
innerstrokedot8(L, T, R, B, blitter);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user