add check/hack to avoid drawing outside of the clip for hairlines

git-svn-id: http://skia.googlecode.com/svn/trunk@134 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-03-23 16:05:19 +00:00
parent ae64551e2e
commit 8898363b2e
3 changed files with 185 additions and 1 deletions

View File

@ -0,0 +1,157 @@
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "Sk64.h"
#include "SkCornerPathEffect.h"
#include "SkGradientShader.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkKernel33MaskFilter.h"
#include "SkPath.h"
#include "SkRandom.h"
#include "SkRegion.h"
#include "SkShader.h"
#include "SkUtils.h"
#include "SkColorPriv.h"
#include "SkColorFilter.h"
#include "SkTime.h"
#include "SkTypeface.h"
#include "SkXfermode.h"
#include "SkStream.h"
#include "SkXMLParser.h"
#include "SkColorPriv.h"
#include "SkImageDecoder.h"
static SkRandom gRand;
static void test_chromium_9005() {
SkBitmap bm;
bm.setConfig(SkBitmap::kARGB_8888_Config, 800, 600);
bm.allocPixels();
SkCanvas canvas(bm);
SkPoint pt0 = { SkFloatToScalar(799.33374f), SkFloatToScalar(1.2360189f) };
SkPoint pt1 = { SkFloatToScalar(808.49969f), SkFloatToScalar(-7.4338055f) };
SkPaint paint;
paint.setAntiAlias(true);
canvas.drawLine(pt0.fX, pt0.fY, pt1.fX, pt1.fY, paint);
}
static void generate_pts(SkPoint pts[], int count, int w, int h) {
for (int i = 0; i < count; i++) {
pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w),
gRand.nextUScalar1() * 3 * h - SkIntToScalar(h));
}
}
static bool check_zeros(const SkPMColor pixels[], int count, int skip) {
for (int i = 0; i < count; i++) {
if (*pixels) {
return false;
}
pixels += skip;
}
return true;
}
static bool check_bitmap_margin(const SkBitmap& bm, int margin) {
size_t rb = bm.rowBytes();
for (int i = 0; i < margin; i++) {
if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) {
return false;
}
int bottom = bm.height() - i - 1;
if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) {
return false;
}
// left column
if (!check_zeros(bm.getAddr32(i, 0), bm.height(), rb >> 2)) {
return false;
}
int right = bm.width() - margin + i;
if (!check_zeros(bm.getAddr32(right, 0), bm.height(), rb >> 2)) {
return false;
}
}
return true;
}
#define WIDTH 80
#define HEIGHT 60
#define MARGIN 4
class HairlineView : public SkView {
public:
HairlineView() {}
protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "Hairines");
return true;
}
return this->INHERITED::onQuery(evt);
}
void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1,
const SkIRect& inset) {
canvas->drawBitmap(b0, 0, 0, NULL);
canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, NULL);
}
void drawBG(SkCanvas* canvas) {
// canvas->drawColor(0xFFDDDDDD);
canvas->drawColor(SK_ColorWHITE);
// canvas->drawColor(SK_ColorBLACK);
}
virtual void onDraw(SkCanvas* canvas) {
this->drawBG(canvas);
if (true) {
test_chromium_9005();
}
SkBitmap bm, bm2;
bm.setConfig(SkBitmap::kARGB_8888_Config,
WIDTH + MARGIN*2,
HEIGHT + MARGIN*2);
bm.allocPixels();
// this will erase our margin, which we want to always stay 0
bm.eraseColor(0);
bm2.setConfig(SkBitmap::kARGB_8888_Config, WIDTH, HEIGHT,
bm.rowBytes());
bm2.setPixels(bm.getAddr32(MARGIN, MARGIN));
SkCanvas c2(bm2);
SkPaint paint;
paint.setAntiAlias(true);
for (int i = 0; i < 10000; i++) {
SkPoint pts[2];
generate_pts(pts, 2, WIDTH, HEIGHT);
bm2.eraseColor(0);
c2.drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
if (!check_bitmap_margin(bm, MARGIN)) {
SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
break;
}
}
this->inval(NULL);
}
private:
typedef SkView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new HairlineView; }
static SkViewRegister reg(MyFactory);

View File

@ -21,6 +21,21 @@
#include "SkRegion.h"
#include "SkFDot6.h"
/* Our attempt to compute the worst case "bounds" for the horizontal and
vertical cases has some numerical bug in it, and we sometimes undervalue
our extends. The bug is that when this happens, we will set the clip to
NULL (for speed), and thus draw outside of the clip by a pixel, which might
only look bad, but it might also access memory outside of the valid range
allcoated for the device bitmap.
This define enables our fix to outset our "bounds" by 1, thus avoiding the
chance of the bug, but at the cost of sometimes taking the rectblitter
case (i.e. not setting the clip to NULL) when we might not actually need
to. If we can improve/fix the actual calculations, then we can remove this
step.
*/
#define OUTSET_BEFORE_CLIP_TEST true
#define HLINE_STACK_BUFFER 100
static inline int SmallDot6Scale(int value, int dot6) {
@ -290,6 +305,10 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
bottom = SkFixedCeil(fstart + SK_FixedHalf);
top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
}
if (OUTSET_BEFORE_CLIP_TEST) {
top -= 1;
bottom += 1;
}
if (top >= clip->fBottom || bottom <= clip->fTop)
return;
if (clip->fTop <= top && clip->fBottom >= bottom)
@ -363,6 +382,10 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
right = SkFixedCeil(fstart + SK_FixedHalf);
left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
}
if (OUTSET_BEFORE_CLIP_TEST) {
left -= 1;
right += 1;
}
if (left >= clip->fRight || right <= clip->fLeft)
return;
if (clip->fLeft <= left && clip->fRight >= right)

View File

@ -65,6 +65,7 @@
007A7CC00F01658C00A2D6EE /* SampleVertices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB10F01658C00A2D6EE /* SampleVertices.cpp */; };
007A7CC10F01658C00A2D6EE /* SampleXfermodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */; };
007C785E0F3B4C230004B142 /* SamplePathClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007C785D0F3B4C230004B142 /* SamplePathClip.cpp */; };
008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 008C4D970F77DAEE0056981C /* SampleHairline.cpp */; };
009CC9190F65918A002185BE /* SampleFontScalerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */; };
00A41E4B0EFC312F00C9CBEB /* SampleArc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */; };
0156F80407C56A3000C6122B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0156F80307C56A3000C6122B /* Foundation.framework */; };
@ -180,6 +181,7 @@
007A7CB10F01658C00A2D6EE /* SampleVertices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleVertices.cpp; path = ../../samplecode/SampleVertices.cpp; sourceTree = SOURCE_ROOT; };
007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleXfermodes.cpp; path = ../../samplecode/SampleXfermodes.cpp; sourceTree = SOURCE_ROOT; };
007C785D0F3B4C230004B142 /* SamplePathClip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SamplePathClip.cpp; path = ../../samplecode/SamplePathClip.cpp; sourceTree = SOURCE_ROOT; };
008C4D970F77DAEE0056981C /* SampleHairline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleHairline.cpp; path = ../../samplecode/SampleHairline.cpp; sourceTree = SOURCE_ROOT; };
009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFontScalerTest.cpp; path = ../../samplecode/SampleFontScalerTest.cpp; sourceTree = SOURCE_ROOT; };
00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleArc.cpp; path = ../../samplecode/SampleArc.cpp; sourceTree = SOURCE_ROOT; };
00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; };
@ -232,6 +234,7 @@
007A7CB10F01658C00A2D6EE /* SampleVertices.cpp */,
007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */,
0041CE1E0F00A12400695E8C /* SampleBitmapRect.cpp */,
008C4D970F77DAEE0056981C /* SampleHairline.cpp */,
0041CE1F0F00A12400695E8C /* SampleCamera.cpp */,
0041CE200F00A12400695E8C /* SampleCircle.cpp */,
0041CE210F00A12400695E8C /* SampleCode.h */,
@ -497,7 +500,6 @@
0041CE400F00A12400695E8C /* SampleFontCache.cpp in Sources */,
0041CE420F00A12400695E8C /* SampleImage.cpp in Sources */,
0041CE430F00A12400695E8C /* SampleLayers.cpp in Sources */,
0041CE440F00A12400695E8C /* SampleLines.cpp in Sources */,
0041CE450F00A12400695E8C /* SampleMeasure.cpp in Sources */,
0041CE480F00A12400695E8C /* SampleOverflow.cpp in Sources */,
0041CE4A0F00A12400695E8C /* SamplePatch.cpp in Sources */,
@ -519,6 +521,8 @@
009CC9190F65918A002185BE /* SampleFontScalerTest.cpp in Sources */,
007A7CB30F01658C00A2D6EE /* SamplePicture.cpp in Sources */,
2714E7960F7733EE00E95AE0 /* SkDrawable.cpp in Sources */,
0041CE440F00A12400695E8C /* SampleLines.cpp in Sources */,
008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};