GiantDashBench(LineType lt, SkScalar width) { fName.printf("giantdashline_%s_%g", LineTypeName(lt), width); fStrokeWidth = width; // deliberately pick intervals that won't be caught by asPoints(), so // we can test the filterPath code-path. const SkScalar intervals[] = { 20, 10, 10, 10 }; fPathEffect.reset(SkDashPathEffect::Create(intervals, SK_ARRAY_COUNT(intervals), 0)); SkScalar cx = 640 / 2; // center X SkScalar cy = 480 / 2; // center Y SkMatrix matrix; switch (lt) { case kHori_LineType: matrix.setIdentity(); break; case kVert_LineType: matrix.setRotate(90, cx, cy); break; case kDiag_LineType: matrix.setRotate(45, cx, cy); break; case kLineTypeCount: // Not a real enum value. break; } const SkScalar overshoot = 100*1000; const SkPoint pts[2] = { { -overshoot, cy }, { 640 + overshoot, cy } }; matrix.mapPoints(fPts, pts, 2); }
void makeMatrices() { { SkMatrix m; m.setIdentity(); fMatrices.push_back(m); } { SkMatrix m; m.setScale(SkIntToScalar(3), SkIntToScalar(2)); fMatrices.push_back(m); } { SkMatrix m; m.setScale(SkIntToScalar(2), SkIntToScalar(2)); fMatrices.push_back(m); } { SkMatrix m; m.setScale(SkIntToScalar(1), SkIntToScalar(2)); fMatrices.push_back(m); } { SkMatrix m; m.setScale(SkIntToScalar(4), SkIntToScalar(1)); fMatrices.push_back(m); } { SkMatrix m; m.setRotate(SkIntToScalar(90)); fMatrices.push_back(m); } { SkMatrix m; m.setSkew(SkIntToScalar(2), SkIntToScalar(3)); fMatrices.push_back(m); } { SkMatrix m; m.setRotate(SkIntToScalar(60)); fMatrices.push_back(m); } }
void Matrix::NativeSetRotate( /* [in] */ Int64 nObj, /* [in] */ Float degrees) { SkMatrix* obj = reinterpret_cast<SkMatrix*>(nObj); obj->setRotate(degrees); }
static void __createRotationMatrix(int rotation, int width, int height, SkMatrix &outMatrix) { // set the position of the image to the middle of the screen outMatrix.setRotate(rotation, width / 2, height / 2); outMatrix.postTranslate((DISPLAY_WIDTH - width) / 2, (DISPLAY_HEIGHT - height) / 2); }
void makeMatrices() { { SkMatrix m; m.setScale(SkIntToScalar(2), SkIntToScalar(3)); fMatrices.push_back(m); } { SkMatrix m; m.setScale(SkIntToScalar(2), SkIntToScalar(2)); fMatrices.push_back(m); } { SkMatrix m; m.setSkew(SkIntToScalar(2), SkIntToScalar(3)); fMatrices.push_back(m); } { SkMatrix m; m.setSkew(SkIntToScalar(2), SkIntToScalar(2)); fMatrices.push_back(m); } { SkMatrix m; m.setRotate(SkIntToScalar(30)); fMatrices.push_back(m); } }
void onDrawContent(SkCanvas* canvas) override { SkISize dsize = canvas->getBaseLayerSize(); canvas->clear(0xFFF0E0F0); for (int i = 0; i < N; ++i) { SkRect rect = SkRect::MakeWH(SkIntToScalar(fRandom.nextRangeU(10, 100)), SkIntToScalar(fRandom.nextRangeU(10, 100))); int x = fRandom.nextRangeU(0, dsize.fWidth); int y = fRandom.nextRangeU(0, dsize.fHeight); canvas->save(); canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); // Uncomment to test rotated rect draw combining. if (false) { SkMatrix rotate; rotate.setRotate(fRandom.nextUScalar1() * 360, SkIntToScalar(x) + SkScalarHalf(rect.fRight), SkIntToScalar(y) + SkScalarHalf(rect.fBottom)); canvas->concat(rotate); } SkRect clipRect = rect; // This clip will always contain the entire rect. It's here to give the GPU op combining // code a little more challenge. clipRect.outset(10, 10); canvas->clipRect(clipRect); SkPaint paint; paint.setColor(fRandom.nextU()); canvas->drawRect(rect, paint); canvas->restore(); } }
void onDraw(int loops, SkCanvas* canvas) override { SkPaint paint; paint.setAntiAlias(fAA); paint.setBlendMode(fMode); SkColor color = start_color(fColorType); int w = this->getSize().x(); int h = this->getSize().y(); static const SkScalar kRectW = 25.1f; static const SkScalar kRectH = 25.9f; if (fColorType == kShaderOpaque_ColorType) { // The only requirement for the shader is that it requires local coordinates SkPoint pts[2] = { {0.0f, 0.0f}, {kRectW, kRectH} }; SkColor colors[] = { color, SK_ColorBLUE }; paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp)); } SkMatrix rotate; // This value was chosen so that we frequently hit the axis-aligned case. rotate.setRotate(30.f, kRectW / 2, kRectH / 2); SkMatrix m = rotate; SkScalar tx = 0, ty = 0; if (fPerspective) { // Apply some fixed perspective to change how ops may draw the rects SkMatrix perspective; perspective.setIdentity(); perspective.setPerspX(1e-4f); perspective.setPerspY(1e-3f); perspective.setSkewX(0.1f); canvas->concat(perspective); } for (int i = 0; i < loops; ++i) { canvas->save(); canvas->translate(tx, ty); canvas->concat(m); paint.setColor(color); color = advance_color(color, fColorType, i); canvas->drawRect(SkRect::MakeWH(kRectW, kRectH), paint); canvas->restore(); tx += kRectW + 2; if (tx > w) { tx = 0; ty += kRectH + 2; if (ty > h) { ty = 0; } } m.postConcat(rotate); } }
virtual void onDraw(SkCanvas* canvas) { SkMatrix m; m.reset(); m.setRotate(33 * SK_Scalar1); m.postScale(3000 * SK_Scalar1, 3000 * SK_Scalar1); m.postTranslate(6000 * SK_Scalar1, -5000 * SK_Scalar1); canvas->concat(m); SkPaint paint; paint.setColor(SK_ColorRED); paint.setAntiAlias(true); bool success = m.invert(&m); SkASSERT(success); (void) success; // silence compiler :( SkPath path; SkPoint pt = {10 * SK_Scalar1, 10 * SK_Scalar1}; SkScalar small = 1 / (500 * SK_Scalar1); m.mapPoints(&pt, 1); path.addCircle(pt.fX, pt.fY, small); canvas->drawPath(path, paint); pt.set(30 * SK_Scalar1, 10 * SK_Scalar1); m.mapPoints(&pt, 1); SkRect rect = {pt.fX - small, pt.fY - small, pt.fX + small, pt.fY + small}; canvas->drawRect(rect, paint); SkBitmap bmp; bmp.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); bmp.allocPixels(); bmp.lockPixels(); uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels()); pixels[0] = SkPackARGB32(0xFF, 0xFF, 0x00, 0x00); pixels[1] = SkPackARGB32(0xFF, 0x00, 0xFF, 0x00); pixels[2] = SkPackARGB32(0x80, 0x00, 0x00, 0x00); pixels[3] = SkPackARGB32(0xFF, 0x00, 0x00, 0xFF); bmp.unlockPixels(); pt.set(30 * SK_Scalar1, 30 * SK_Scalar1); m.mapPoints(&pt, 1); SkShader* shader = SkShader::CreateBitmapShader( bmp, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix s; s.reset(); s.setScale(SK_Scalar1 / 1000, SK_Scalar1 / 1000); shader->setLocalMatrix(s); paint.setShader(shader)->unref(); paint.setAntiAlias(false); paint.setFilterLevel(SkPaint::kLow_FilterLevel); rect.setLTRB(pt.fX - small, pt.fY - small, pt.fX + small, pt.fY + small); canvas->drawRect(rect, paint); }
// Create a selection of imagefilter-based paints to test static void create_paints(SkImageFilter* source, SkTArray<SkPaint>* paints) { { SkMatrix scale; scale.setScale(2.0f, 2.0f); SkAutoTUnref<SkImageFilter> scaleMIF( SkImageFilter::CreateMatrixFilter(scale, kLow_SkFilterQuality, source)); add_paint(scaleMIF, paints); } { SkMatrix rot; rot.setRotate(-33.3f); SkAutoTUnref<SkImageFilter> rotMIF( SkImageFilter::CreateMatrixFilter(rot, kLow_SkFilterQuality, source)); add_paint(rotMIF, paints); } { static const SkDropShadowImageFilter::ShadowMode kBoth = SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode; SkAutoTUnref<SkDropShadowImageFilter> dsif( SkDropShadowImageFilter::Create(10.0f, 10.0f, 3.0f, 3.0f, SK_ColorRED, kBoth, source, nullptr)); add_paint(dsif, paints); } { SkAutoTUnref<SkDropShadowImageFilter> dsif( SkDropShadowImageFilter::Create(27.0f, 27.0f, 3.0f, 3.0f, SK_ColorRED, SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, source, nullptr)); add_paint(dsif, paints); } { SkAutoTUnref<SkBlurImageFilter> bif(SkBlurImageFilter::Create(3, 3, source)); add_paint(bif, paints); } { SkAutoTUnref<SkOffsetImageFilter> oif(SkOffsetImageFilter::Create(15, 15, source)); add_paint(oif, paints); } }
bool SkDrawMatrix::setProperty(int index, SkScriptValue& scriptValue) { SkScalar number = scriptValue.fOperand.fScalar; switch (index) { case SK_PROPERTY(translate): // SkScalar xy[2]; SkASSERT(scriptValue.fType == SkType_Array); SkASSERT(scriptValue.fOperand.fArray->getType() == SkType_Float); SkASSERT(scriptValue.fOperand.fArray->count() == 2); // SkParse::FindScalars(scriptValue.fOperand.fString->c_str(), xy, 2); fMatrix.setTranslateX((*scriptValue.fOperand.fArray)[0].fScalar); fMatrix.setTranslateY((*scriptValue.fOperand.fArray)[1].fScalar); return true; case SK_PROPERTY(perspectX): fMatrix.setPerspX(SkScalarToPersp((number))); break; case SK_PROPERTY(perspectY): fMatrix.setPerspY(SkScalarToPersp((number))); break; case SK_PROPERTY(rotate): { SkMatrix temp; temp.setRotate(number, 0, 0); fMatrix.setScaleX(temp.getScaleX()); fMatrix.setScaleY(temp.getScaleY()); fMatrix.setSkewX(temp.getSkewX()); fMatrix.setSkewY(temp.getSkewY()); } break; case SK_PROPERTY(scale): fMatrix.setScaleX(number); fMatrix.setScaleY(number); break; case SK_PROPERTY(scaleX): fMatrix.setScaleX(number); break; case SK_PROPERTY(scaleY): fMatrix.setScaleY(number); break; case SK_PROPERTY(skewX): fMatrix.setSkewX(number); break; case SK_PROPERTY(skewY): fMatrix.setSkewY(number); break; case SK_PROPERTY(translateX): fMatrix.setTranslateX(number); break; case SK_PROPERTY(translateY): fMatrix.setTranslateY(number); break; default: SkASSERT(0); return false; } fConcat = fMatrix; return true; }
void makeMatrices() { { // 1x1.5 scale SkMatrix m; m.setScale(1, 1.5f); fMatrices.push_back(m); } { // 1.5x1.5 scale SkMatrix m; m.setScale(1.5f, 1.5f); fMatrices.push_back(m); } { // 1x1.5 skew SkMatrix m; m.setSkew(1, 1.5f); fMatrices.push_back(m); } { // 1.5x1.5 skew SkMatrix m; m.setSkew(1.5f, 1.5f); fMatrices.push_back(m); } { // 30 degree rotation SkMatrix m; m.setRotate(SkIntToScalar(30)); fMatrices.push_back(m); } { // 90 degree rotation SkMatrix m; m.setRotate(SkIntToScalar(90)); fMatrices.push_back(m); } }
// Create a selection of imagefilter-based paints to test static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) { { SkMatrix scale; scale.setScale(2.0f, 2.0f); sk_sp<SkImageFilter> scaleMIF( SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source)); add_paint(paints, std::move(scaleMIF)); } { SkMatrix rot; rot.setRotate(-33.3f); sk_sp<SkImageFilter> rotMIF( SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source)); add_paint(paints, std::move(rotMIF)); } { SkRect src = SkRect::MakeXYWH(20, 20, 10, 10); SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30); sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr)); add_paint(paints, std::move(tileIF)); } { constexpr SkDropShadowImageFilter::ShadowMode kBoth = SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode; sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f, 3.0f, 3.0f, SK_ColorRED, kBoth, source)); add_paint(paints, std::move(dsif)); } { sk_sp<SkImageFilter> dsif( SkDropShadowImageFilter::Make(27.0f, 27.0f, 3.0f, 3.0f, SK_ColorRED, SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, source)); add_paint(paints, std::move(dsif)); } add_paint(paints, SkBlurImageFilter::Make(3, 3, source)); add_paint(paints, SkOffsetImageFilter::Make(15, 15, source)); }
void draw(SkCanvas* canvas) { SkPath path; path.moveTo(100, 100); path.quadTo(100, 20, 20, 100); SkMatrix matrix; matrix.setRotate(36, 100, 100); path.transform(matrix); SkPoint last; path.getLastPt(&last); SkDebugf("last point: %g, %g\n", last.fX, last.fY); }
void drawShape(SkCanvas* canvas, SkPaint* paint, ShapeType type) { static const SkRect kRect = SkRect::MakeXYWH(SkIntToScalar(-50), SkIntToScalar(-50), SkIntToScalar(75), SkIntToScalar(105)); switch (type) { case kCircle_ShapeType: canvas->drawCircle(0, 0, 50, *paint); break; case kRoundRect_ShapeType: canvas->drawRoundRect(kRect, SkIntToScalar(10), SkIntToScalar(20), *paint); break; case kRect_ShapeType: canvas->drawRect(kRect, *paint); break; case kConvexPath_ShapeType: if (fConvexPath.isEmpty()) { SkPoint points[4]; kRect.toQuad(points); fConvexPath.moveTo(points[0]); fConvexPath.quadTo(points[1], points[2]); fConvexPath.quadTo(points[3], points[0]); SkASSERT(fConvexPath.isConvex()); } canvas->drawPath(fConvexPath, *paint); break; case kConcavePath_ShapeType: if (fConcavePath.isEmpty()) { SkPoint points[5] = {{0, SkIntToScalar(-50)} }; SkMatrix rot; rot.setRotate(SkIntToScalar(360) / 5); for (int i = 1; i < 5; ++i) { rot.mapPoints(points + i, points + i - 1, 1); } fConcavePath.moveTo(points[0]); for (int i = 0; i < 5; ++i) { fConcavePath.lineTo(points[(2 * i) % 5]); } fConcavePath.setFillType(SkPath::kEvenOdd_FillType); SkASSERT(!fConcavePath.isConvex()); } canvas->drawPath(fConcavePath, *paint); break; case kText_ShapeType: { const char* text = "Hello!"; paint->setTextSize(30); sk_tool_utils::set_portable_typeface(paint); canvas->drawText(text, strlen(text), 0, 0, *paint); } default: break; } }
void PathBuilderSkia::Arc(const Point &aOrigin, float aRadiusX, float aRadiusY, float aRotationAngle, float aStartAngle, float aEndAngle, bool aAntiClockwise) { ArcToBezier<PathBuilder>(this, aOrigin, Size(aRadiusX, aRadiusY), aStartAngle, aEndAngle, aAntiClockwise); if (aRotationAngle) { SkMatrix matrix; matrix.setRotate(aRotationAngle * 180.0 / M_PI, aOrigin.x, aOrigin.y); mPath.transform(matrix); } }
void onDraw(SkCanvas* canvas) override { static const int kOn = 4; static const int kOff = 4; static const int kIntervalLength = kOn + kOff; static const SkColor gColors[kIntervalLength] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW, SK_ColorGRAY, SK_ColorDKGRAY }; SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(fDoAA); SkMatrix rot; rot.setRotate(90); SkASSERT(rot.rectStaysRect()); canvas->concat(rot); int sign; // used to toggle the direction of the lines int phase = 0; for (int x = 0; x < 200; x += 10) { paint.setStrokeWidth(SkIntToScalar(phase+1)); paint.setColor(gColors[phase]); sign = (x % 20) ? 1 : -1; drawline(canvas, kOn, kOff, paint, SkIntToScalar(x), -sign * SkIntToScalar(10003), SkIntToScalar(phase), SkIntToScalar(x), sign * SkIntToScalar(10003)); phase = (phase + 1) % kIntervalLength; } for (int y = -400; y < 0; y += 10) { paint.setStrokeWidth(SkIntToScalar(phase+1)); paint.setColor(gColors[phase]); sign = (y % 20) ? 1 : -1; drawline(canvas, kOn, kOff, paint, -sign * SkIntToScalar(10003), SkIntToScalar(y), SkIntToScalar(phase), sign * SkIntToScalar(10003), SkIntToScalar(y)); phase = (phase + 1) % kIntervalLength; } }
static void test_decompScale(skiatest::Reporter* reporter) { SkMatrix m; m.reset(); REPORTER_ASSERT(reporter, check_decompScale(m)); m.setScale(2, 3); REPORTER_ASSERT(reporter, check_decompScale(m)); m.setRotate(35, 0, 0); REPORTER_ASSERT(reporter, check_decompScale(m)); m.setScale(1, 0); REPORTER_ASSERT(reporter, !check_decompScale(m)); }
void draw(SkCanvas* canvas) { auto debugster = [](const char* prefix, const SkPath& path) -> void { const SkRect& bounds = path.getBounds(); SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); }; SkPath path; debugster("empty", path); path.addCircle(50, 45, 25); debugster("circle", path); SkMatrix matrix; matrix.setRotate(45, 50, 45); path.transform(matrix); debugster("rotated circle", path); }
ImageView() { SkImageRef_GlobalPool::SetRAMBudget(32 * 1024); int i, N = SK_ARRAY_COUNT(gNames); fBitmaps = new SkBitmap[N]; for (i = 0; i < N; i++) { SkString str("/skimages/"); str.append(gNames[i]); SkFILEStream* stream = new SkFILEStream(str.c_str()); SetImageRef(&fBitmaps[i], stream, SkBitmap::kNo_Config, gNames[i]); if (i & 1) fBitmaps[i].buildMipMap(); stream->unref(); } fShader = SkShader::CreateBitmapShader(fBitmaps[5], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); if (true) { SkMatrix m; m.setRotate(SkIntToScalar(30)); fShader->setLocalMatrix(m); } #if 0 SkImageRef::DumpPool(); for (i = 0; i < N; i++) { SkBitmap& bm = fBitmaps[i]; SkDebugf("<%s> addr=%p", gNames[i], bm.getPixels()); bool success = bm.lockPixels(); SkDebugf(" addr=%d", bm.getPixels()); if (success) bm.unlockPixels(); SkDebugf(" addr=%p", bm.getPixels()); success = bm.lockPixels(); SkDebugf(" addr=%d", bm.getPixels()); if (success) bm.unlockPixels(); SkDebugf("\n"); } SkImageRef::DumpPool(); #endif }
void onDrawContent(SkCanvas* canvas) override { const int nu = 10; const int nv = 10; SkPaint paint; paint.setDither(true); paint.setFilterQuality(kLow_SkFilterQuality); canvas->translate(DX, DY); Patch patch; paint.setShader(fShader0); if (fSize0.fX == 0) { fSize0.fX = 1; } if (fSize0.fY == 0) { fSize0.fY = 1; } patch.setBounds(fSize0.fX, fSize0.fY); patch.setPatch(fPts); drawpatches(canvas, paint, nu, nv, &patch); paint.setShader(nullptr); paint.setAntiAlias(true); paint.setStrokeWidth(SkIntToScalar(5)); canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts), fPts, paint); canvas->translate(0, SkIntToScalar(300)); paint.setAntiAlias(false); paint.setShader(fShader1); if (true) { SkMatrix m; m.setSkew(1, 0); SkShader* s = SkShader::CreateLocalMatrixShader(paint.getShader(), m); paint.setShader(s)->unref(); } if (true) { SkMatrix m; m.setRotate(fAngle); SkShader* s = SkShader::CreateLocalMatrixShader(paint.getShader(), m); paint.setShader(s)->unref(); } patch.setBounds(fSize1.fX, fSize1.fY); drawpatches(canvas, paint, nu, nv, &patch); }
ShapesGM() { SkMatrix m; fGroup.appendShape(make_shape0(false))->unref(); m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50)); m.postTranslate(0, SkIntToScalar(120)); fGroup.appendShape(make_shape0(true), m)->unref(); m.setTranslate(SkIntToScalar(120), 0); fGroup.appendShape(make_shape1(), m)->unref(); m.postTranslate(0, SkIntToScalar(120)); fGroup.appendShape(make_shape2(), m)->unref(); for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) { SkSafeRef(fMatrixRefs[i] = fGroup.getShapeMatrixRef(i)); } }
SkLayerView() { test44(); static const int W = 600; static const int H = 440; static const struct { int fWidth; int fHeight; SkColor fColor; int fPosX; int fPosY; } gData[] = { { 120, 80, SK_ColorRED, 0, 0 }, { 120, 80, SK_ColorGREEN, W - 120, 0 }, { 120, 80, SK_ColorBLUE, 0, H - 80 }, { 120, 80, SK_ColorMAGENTA, W - 120, H - 80 }, }; fRootLayer = new TestLayer(0xFFDDDDDD); fRootLayer->setSize(W, H); for (size_t i = 0; i < SK_ARRAY_COUNT(gData); i++) { SkLayer* child = new TestLayer(gData[i].fColor); child->setSize(gData[i].fWidth, gData[i].fHeight); child->setPosition(gData[i].fPosX, gData[i].fPosY); fRootLayer->addChild(child)->unref(); } SkLayer* child = new TestLayer(0xFFDD8844); child->setSize(120, 80); child->setPosition(fRootLayer->getWidth()/2 - child->getWidth()/2, fRootLayer->getHeight()/2 - child->getHeight()/2); child->setAnchorPoint(SK_ScalarHalf, SK_ScalarHalf); { SkMatrix m; m.setRotate(SkIntToScalar(30)); child->setMatrix(m); } fLastChild = child; fRootLayer->addChild(child)->unref(); if (false) { SkMatrix matrix; matrix.setScale(0.5, 0.5); fRootLayer->setMatrix(matrix); } // dump_layers(fRootLayer); }
// Creates a star type shape using a SkPath static SkPath create_star() { static const int kNumPoints = 5; SkPath concavePath; SkPoint points[kNumPoints] = {{0, SkIntToScalar(-50)} }; SkMatrix rot; rot.setRotate(SkIntToScalar(360) / kNumPoints); for (int i = 1; i < kNumPoints; ++i) { rot.mapPoints(points + i, points + i - 1, 1); } concavePath.moveTo(points[0]); for (int i = 0; i < kNumPoints; ++i) { concavePath.lineTo(points[(2 * i) % kNumPoints]); } concavePath.setFillType(SkPath::kEvenOdd_FillType); SkASSERT(!concavePath.isConvex()); concavePath.close(); return concavePath; }
virtual void recordCanvas(SkCanvas* canvas) { const SkPoint translateDelta = getTranslateDelta(); for (int i = 0; i < M; i++) { SkColor color = SK_ColorYELLOW + (i % 255); SkIRect rect = SkIRect::MakeWH(i,i); canvas->save(); // set the clip to the given region SkRegion region; region.setRect(rect); canvas->clipRegion(region); // fill the clip with a color SkPaint paint; paint.setColor(color); canvas->drawPaint(paint); // set a matrix on the canvas SkMatrix matrix; matrix.setRotate(SkIntToScalar(i % 360)); canvas->setMatrix(matrix); // create a simple bitmap SkBitmap bitmap; bitmap.setConfig(SkBitmap::kRGB_565_Config, 10, 10); bitmap.allocPixels(); // draw a single color into the bitmap SkCanvas bitmapCanvas(bitmap); bitmapCanvas.drawColor(SkColorSetA(color, i % 255)); // draw the bitmap onto the canvas canvas->drawBitmapMatrix(bitmap, matrix); canvas->restore(); canvas->translate(translateDelta.fX, translateDelta.fY); } }
void onDraw(int loops, SkCanvas* canvas) override { SkPaint paint; paint.setAntiAlias(fAA); paint.setXfermodeMode(fMode); SkColor color = start_color(fColorType); int w = this->getSize().x(); int h = this->getSize().y(); static const SkScalar kRectW = 25.1f; static const SkScalar kRectH = 25.9f; SkMatrix rotate; // This value was chosen so that we frequently hit the axis-aligned case. rotate.setRotate(30.f, kRectW / 2, kRectH / 2); SkMatrix m = rotate; SkScalar tx = 0, ty = 0; for (int i = 0; i < loops; ++i) { canvas->save(); canvas->translate(tx, ty); canvas->concat(m); paint.setColor(color); color = advance_color(color, fColorType, i); canvas->drawRect(SkRect::MakeWH(kRectW, kRectH), paint); canvas->restore(); tx += kRectW + 2; if (tx > w) { tx = 0; ty += kRectH + 2; if (ty > h) { ty = 0; } } m.postConcat(rotate); } }
void GM::DrawGpuOnlyMessage(SkCanvas* canvas) { SkBitmap bmp; bmp.allocN32Pixels(128, 64); SkCanvas bmpCanvas(bmp); bmpCanvas.drawColor(SK_ColorWHITE); SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(20); paint.setColor(SK_ColorRED); sk_tool_utils::set_portable_typeface(&paint); static const char kTxt[] = "GPU Only"; bmpCanvas.drawText(kTxt, strlen(kTxt), 20, 40, paint); SkMatrix localM; localM.setRotate(35.f); localM.postTranslate(10.f, 0.f); paint.setShader(SkShader::MakeBitmapShader(bmp, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode, &localM)); paint.setFilterQuality(kMedium_SkFilterQuality); canvas->drawPaint(paint); return; }
static void test_matrix_homogeneous(skiatest::Reporter* reporter) { SkMatrix mat; const float kRotation0 = 15.5f; const float kRotation1 = -50.f; const float kScale0 = 5000.f; const int kTripleCount = 1000; const int kMatrixCount = 1000; SkRandom rand; SkScalar randTriples[3*kTripleCount]; for (int i = 0; i < 3*kTripleCount; ++i) { randTriples[i] = rand.nextRangeF(-3000.f, 3000.f); } SkMatrix mats[kMatrixCount]; for (int i = 0; i < kMatrixCount; ++i) { for (int j = 0; j < 9; ++j) { mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f)); } } // identity { mat.reset(); SkScalar dst[3*kTripleCount]; mat.mapHomogeneousPoints(dst, randTriples, kTripleCount); REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(randTriples, dst, kTripleCount*3)); } // zero matrix { mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f); SkScalar dst[3*kTripleCount]; mat.mapHomogeneousPoints(dst, randTriples, kTripleCount); SkScalar zeros[3] = {0.f, 0.f, 0.f}; for (int i = 0; i < kTripleCount; ++i) { REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(&dst[i*3], zeros, 3)); } } // zero point { SkScalar zeros[3] = {0.f, 0.f, 0.f}; for (int i = 0; i < kMatrixCount; ++i) { SkScalar dst[3]; mats[i].mapHomogeneousPoints(dst, zeros, 1); REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(dst, zeros, 3)); } } // doesn't crash with null dst, src, count == 0 { mats[0].mapHomogeneousPoints(NULL, NULL, 0); } // uniform scale of point { mat.setScale(kScale0, kScale0); SkScalar dst[3]; SkScalar src[3] = {randTriples[0], randTriples[1], 1.f}; SkPoint pnt; pnt.set(src[0], src[1]); mat.mapHomogeneousPoints(dst, src, 1); mat.mapPoints(&pnt, &pnt, 1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1)); } // rotation of point { mat.setRotate(kRotation0); SkScalar dst[3]; SkScalar src[3] = {randTriples[0], randTriples[1], 1.f}; SkPoint pnt; pnt.set(src[0], src[1]); mat.mapHomogeneousPoints(dst, src, 1); mat.mapPoints(&pnt, &pnt, 1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1)); } // rotation, scale, rotation of point { mat.setRotate(kRotation1); mat.postScale(kScale0, kScale0); mat.postRotate(kRotation0); SkScalar dst[3]; SkScalar src[3] = {randTriples[0], randTriples[1], 1.f}; SkPoint pnt; pnt.set(src[0], src[1]); mat.mapHomogeneousPoints(dst, src, 1); mat.mapPoints(&pnt, &pnt, 1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1)); } // compare with naive approach { for (int i = 0; i < kMatrixCount; ++i) { for (int j = 0; j < kTripleCount; ++j) { SkScalar dst[3]; mats[i].mapHomogeneousPoints(dst, &randTriples[j*3], 1); REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], &randTriples[j*3], dst)); } } } }
static void test_matrix_decomposition(skiatest::Reporter* reporter) { SkMatrix mat; SkPoint rotation1, scale, rotation2; const float kRotation0 = 15.5f; const float kRotation1 = -50.f; const float kScale0 = 5000.f; const float kScale1 = 0.001f; // identity mat.reset(); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // make sure it doesn't crash if we pass in NULLs REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, NULL, NULL, NULL)); // rotation only mat.setRotate(kRotation0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // uniform scale only mat.setScale(kScale0, kScale0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // anisotropic scale only mat.setScale(kScale1, kScale0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation then uniform scale mat.setRotate(kRotation1); mat.postScale(kScale0, kScale0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // uniform scale then rotation mat.setScale(kScale0, kScale0); mat.postRotate(kRotation1); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation then uniform scale+reflection mat.setRotate(kRotation0); mat.postScale(kScale1, -kScale1); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // uniform scale+reflection, then rotate mat.setScale(kScale0, -kScale0); mat.postRotate(kRotation1); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation then anisotropic scale mat.setRotate(kRotation1); mat.postScale(kScale1, kScale0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation then anisotropic scale mat.setRotate(90); mat.postScale(kScale1, kScale0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // anisotropic scale then rotation mat.setScale(kScale1, kScale0); mat.postRotate(kRotation0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // anisotropic scale then rotation mat.setScale(kScale1, kScale0); mat.postRotate(90); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation, uniform scale, then different rotation mat.setRotate(kRotation1); mat.postScale(kScale0, kScale0); mat.postRotate(kRotation0); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation, anisotropic scale, then different rotation mat.setRotate(kRotation0); mat.postScale(kScale1, kScale0); mat.postRotate(kRotation1); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // rotation, anisotropic scale + reflection, then different rotation mat.setRotate(kRotation0); mat.postScale(-kScale1, kScale0); mat.postRotate(kRotation1); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // try some random matrices SkRandom rand; for (int m = 0; m < 1000; ++m) { SkScalar rot0 = rand.nextRangeF(-180, 180); SkScalar sx = rand.nextRangeF(-3000.f, 3000.f); SkScalar sy = rand.nextRangeF(-3000.f, 3000.f); SkScalar rot1 = rand.nextRangeF(-180, 180); mat.setRotate(rot0); mat.postScale(sx, sy); mat.postRotate(rot1); if (SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)) { REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); } else { // if the matrix is degenerate, the basis vectors should be near-parallel or near-zero SkScalar perpdot = mat[SkMatrix::kMScaleX]*mat[SkMatrix::kMScaleY] - mat[SkMatrix::kMSkewX]*mat[SkMatrix::kMSkewY]; REPORTER_ASSERT(reporter, SkScalarNearlyZero(perpdot)); } } // translation shouldn't affect this mat.postTranslate(-1000.f, 1000.f); REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // perspective shouldn't affect this mat[SkMatrix::kMPersp0] = 12.f; mat[SkMatrix::kMPersp1] = 4.f; mat[SkMatrix::kMPersp2] = 1872.f; REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2)); // degenerate matrices // mostly zero entries mat.reset(); mat[SkMatrix::kMScaleX] = 0.f; REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); mat.reset(); mat[SkMatrix::kMScaleY] = 0.f; REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); mat.reset(); // linearly dependent entries mat[SkMatrix::kMScaleX] = 1.f; mat[SkMatrix::kMSkewX] = 2.f; mat[SkMatrix::kMSkewY] = 4.f; mat[SkMatrix::kMScaleY] = 8.f; REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)); }
static void test_matrix_is_similarity(skiatest::Reporter* reporter) { SkMatrix mat; // identity mat.setIdentity(); REPORTER_ASSERT(reporter, mat.isSimilarity()); // translation only mat.reset(); mat.setTranslate(SkIntToScalar(100), SkIntToScalar(100)); REPORTER_ASSERT(reporter, mat.isSimilarity()); // scale with same size mat.reset(); mat.setScale(SkIntToScalar(15), SkIntToScalar(15)); REPORTER_ASSERT(reporter, mat.isSimilarity()); // scale with one negative mat.reset(); mat.setScale(SkIntToScalar(-15), SkIntToScalar(15)); REPORTER_ASSERT(reporter, mat.isSimilarity()); // scale with different size mat.reset(); mat.setScale(SkIntToScalar(15), SkIntToScalar(20)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // scale with same size at a pivot point mat.reset(); mat.setScale(SkIntToScalar(15), SkIntToScalar(15), SkIntToScalar(2), SkIntToScalar(2)); REPORTER_ASSERT(reporter, mat.isSimilarity()); // scale with different size at a pivot point mat.reset(); mat.setScale(SkIntToScalar(15), SkIntToScalar(20), SkIntToScalar(2), SkIntToScalar(2)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // skew with same size mat.reset(); mat.setSkew(SkIntToScalar(15), SkIntToScalar(15)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // skew with different size mat.reset(); mat.setSkew(SkIntToScalar(15), SkIntToScalar(20)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // skew with same size at a pivot point mat.reset(); mat.setSkew(SkIntToScalar(15), SkIntToScalar(15), SkIntToScalar(2), SkIntToScalar(2)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // skew with different size at a pivot point mat.reset(); mat.setSkew(SkIntToScalar(15), SkIntToScalar(20), SkIntToScalar(2), SkIntToScalar(2)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // perspective x mat.reset(); mat.setPerspX(SkScalarToPersp(SK_Scalar1 / 2)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // perspective y mat.reset(); mat.setPerspY(SkScalarToPersp(SK_Scalar1 / 2)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // rotate for (int angle = 0; angle < 360; ++angle) { mat.reset(); mat.setRotate(SkIntToScalar(angle)); REPORTER_ASSERT(reporter, mat.isSimilarity()); } // see if there are any accumulated precision issues mat.reset(); for (int i = 1; i < 360; i++) { mat.postRotate(SkIntToScalar(1)); } REPORTER_ASSERT(reporter, mat.isSimilarity()); // rotate + translate mat.reset(); mat.setRotate(SkIntToScalar(30)); mat.postTranslate(SkIntToScalar(10), SkIntToScalar(20)); REPORTER_ASSERT(reporter, mat.isSimilarity()); // rotate + uniform scale mat.reset(); mat.setRotate(SkIntToScalar(30)); mat.postScale(SkIntToScalar(2), SkIntToScalar(2)); REPORTER_ASSERT(reporter, mat.isSimilarity()); // rotate + non-uniform scale mat.reset(); mat.setRotate(SkIntToScalar(30)); mat.postScale(SkIntToScalar(3), SkIntToScalar(2)); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // all zero mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 0); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // all zero except perspective mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, SK_Scalar1); REPORTER_ASSERT(reporter, !mat.isSimilarity()); // scales zero, only skews mat.setAll(0, SK_Scalar1, 0, SK_Scalar1, 0, 0, 0, 0, SkMatrix::I()[8]); REPORTER_ASSERT(reporter, mat.isSimilarity()); }
static void test_matrix_min_max_scale(skiatest::Reporter* reporter) { SkScalar scales[2]; bool success; SkMatrix identity; identity.reset(); REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMinScale()); REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxScale()); success = identity.getMinMaxScales(scales); REPORTER_ASSERT(reporter, success && SK_Scalar1 == scales[0] && SK_Scalar1 == scales[1]); SkMatrix scale; scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4); REPORTER_ASSERT(reporter, SK_Scalar1 * 2 == scale.getMinScale()); REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxScale()); success = scale.getMinMaxScales(scales); REPORTER_ASSERT(reporter, success && SK_Scalar1 * 2 == scales[0] && SK_Scalar1 * 4 == scales[1]); SkMatrix rot90Scale; rot90Scale.setRotate(90 * SK_Scalar1); rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2); REPORTER_ASSERT(reporter, SK_Scalar1 / 4 == rot90Scale.getMinScale()); REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxScale()); success = rot90Scale.getMinMaxScales(scales); REPORTER_ASSERT(reporter, success && SK_Scalar1 / 4 == scales[0] && SK_Scalar1 / 2 == scales[1]); SkMatrix rotate; rotate.setRotate(128 * SK_Scalar1); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMinScale(), SK_ScalarNearlyZero)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMaxScale(), SK_ScalarNearlyZero)); success = rotate.getMinMaxScales(scales); REPORTER_ASSERT(reporter, success); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, scales[0], SK_ScalarNearlyZero)); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, scales[1], SK_ScalarNearlyZero)); SkMatrix translate; translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1); REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMinScale()); REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxScale()); success = translate.getMinMaxScales(scales); REPORTER_ASSERT(reporter, success && SK_Scalar1 == scales[0] && SK_Scalar1 == scales[1]); SkMatrix perspX; perspX.reset(); perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000)); REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMinScale()); REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxScale()); // Verify that getMinMaxScales() doesn't update the scales array on failure. scales[0] = -5; scales[1] = -5; success = perspX.getMinMaxScales(scales); REPORTER_ASSERT(reporter, !success && -5 * SK_Scalar1 == scales[0] && -5 * SK_Scalar1 == scales[1]); SkMatrix perspY; perspY.reset(); perspY.setPerspY(SkScalarToPersp(-SK_Scalar1 / 500)); REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMinScale()); REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxScale()); scales[0] = -5; scales[1] = -5; success = perspY.getMinMaxScales(scales); REPORTER_ASSERT(reporter, !success && -5 * SK_Scalar1 == scales[0] && -5 * SK_Scalar1 == scales[1]); SkMatrix baseMats[] = {scale, rot90Scale, rotate, translate, perspX, perspY}; SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)]; for (size_t i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) { mats[i] = baseMats[i]; bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]); REPORTER_ASSERT(reporter, invertable); } SkRandom rand; for (int m = 0; m < 1000; ++m) { SkMatrix mat; mat.reset(); for (int i = 0; i < 4; ++i) { int x = rand.nextU() % SK_ARRAY_COUNT(mats); mat.postConcat(mats[x]); } SkScalar minScale = mat.getMinScale(); SkScalar maxScale = mat.getMaxScale(); REPORTER_ASSERT(reporter, (minScale < 0) == (maxScale < 0)); REPORTER_ASSERT(reporter, (maxScale < 0) == mat.hasPerspective()); SkScalar scales[2]; bool success = mat.getMinMaxScales(scales); REPORTER_ASSERT(reporter, success == !mat.hasPerspective()); REPORTER_ASSERT(reporter, !success || (scales[0] == minScale && scales[1] == maxScale)); if (mat.hasPerspective()) { m -= 1; // try another non-persp matrix continue; } // test a bunch of vectors. All should be scaled by between minScale and maxScale // (modulo some error) and we should find a vector that is scaled by almost each. static const SkScalar gVectorScaleTol = (105 * SK_Scalar1) / 100; static const SkScalar gCloseScaleTol = (97 * SK_Scalar1) / 100; SkScalar max = 0, min = SK_ScalarMax; SkVector vectors[1000]; for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) { vectors[i].fX = rand.nextSScalar1(); vectors[i].fY = rand.nextSScalar1(); if (!vectors[i].normalize()) { i -= 1; continue; } } mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors)); for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) { SkScalar d = vectors[i].length(); REPORTER_ASSERT(reporter, SkScalarDiv(d, maxScale) < gVectorScaleTol); REPORTER_ASSERT(reporter, SkScalarDiv(minScale, d) < gVectorScaleTol); if (max < d) { max = d; } if (min > d) { min = d; } } REPORTER_ASSERT(reporter, SkScalarDiv(max, maxScale) >= gCloseScaleTol); REPORTER_ASSERT(reporter, SkScalarDiv(minScale, min) >= gCloseScaleTol); } }