paint.setShader(SkGradientShader::MakeLinear(kPts1, kColors1, kPos, SK_ARRAY_COUNT(kColors1), SkShader::kClamp_TileMode)); canvas.drawPaint(paint); } /////////////////////////////////////////////////////////////////////////////// struct LabeledMatrix { SkMatrix fMatrix; const char* fLabel; }; DEF_SIMPLE_GM_BG(shadertext2, canvas, 1800, 900, sk_tool_utils::color_to_565(0xFFDDDDDD)) { static const char kText[] = "SKIA"; static const int kTextLen = SK_ARRAY_COUNT(kText) - 1; static const int kPointSize = 55; SkTDArray<LabeledMatrix> matrices; matrices.append()->fMatrix.reset(); matrices.top().fLabel = "Identity"; matrices.append()->fMatrix.setScale(1.2f, 0.8f); matrices.top().fLabel = "Scale"; matrices.append()->fMatrix.setRotate(10.f); matrices.top().fLabel = "Rotate"; matrices.append()->fMatrix.reset(); matrices.top().fMatrix.setPerspX(-0.0015f); matrices.top().fMatrix.setPerspY(+0.0015f); matrices.top().fLabel = "Persp"; SkTDArray<LabeledMatrix> localMatrices;
virtual void onDrawContent(SkCanvas* canvas) { const char text[] = "Shaded Text"; const int textLen = SK_ARRAY_COUNT(text) - 1; static int pointSize = 36; int w = pointSize * textLen; int h = pointSize; SkPoint pts[2] = { { 0, 0 }, { SkIntToScalar(w), SkIntToScalar(h) } }; SkScalar textBase = SkIntToScalar(h/2); SkShader::TileMode tileModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode }; static const int gradCount = SK_ARRAY_COUNT(gGradData) * SK_ARRAY_COUNT(gGradMakers); static const int bmpCount = SK_ARRAY_COUNT(tileModes) * SK_ARRAY_COUNT(tileModes); SkShader* shaders[gradCount + bmpCount]; int shdIdx = 0; for (size_t d = 0; d < SK_ARRAY_COUNT(gGradData); ++d) { for (size_t m = 0; m < SK_ARRAY_COUNT(gGradMakers); ++m) { shaders[shdIdx++] = gGradMakers[m](pts, gGradData[d], SkShader::kClamp_TileMode); } } for (size_t tx = 0; tx < SK_ARRAY_COUNT(tileModes); ++tx) { for (size_t ty = 0; ty < SK_ARRAY_COUNT(tileModes); ++ty) { shaders[shdIdx++] = MakeBitmapShader(tileModes[tx], tileModes[ty], w/8, h); } } SkPaint paint; paint.setDither(true); paint.setAntiAlias(true); paint.setTextSize(SkIntToScalar(pointSize)); canvas->save(); canvas->translate(SkIntToScalar(20), SkIntToScalar(10)); SkPath path; path.arcTo(SkRect::MakeXYWH(SkIntToScalar(-40), SkIntToScalar(15), SkIntToScalar(300), SkIntToScalar(90)), SkIntToScalar(225), SkIntToScalar(90), false); path.close(); static const int testsPerCol = 8; static const int rowHeight = 60; static const int colWidth = 300; canvas->save(); for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) { canvas->save(); size_t i = 2*s; canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth), SkIntToScalar((i % testsPerCol) * rowHeight)); paint.setShader(shaders[s])->unref(); canvas->drawText(text, textLen, 0, textBase, paint); canvas->restore(); canvas->save(); ++i; canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth), SkIntToScalar((i % testsPerCol) * rowHeight)); canvas->drawTextOnPath(text, textLen, path, NULL, paint); canvas->restore(); } canvas->restore(); canvas->translate(0, SkIntToScalar(370)); this->inval(NULL); }
static void test_isfinite(skiatest::Reporter* reporter) { struct Rec { float fValue; bool fIsFinite; }; float max = 3.402823466e+38f; float inf = max * max; float nan = inf * 0; test_floatclass(reporter, 0, kFinite); test_floatclass(reporter, max, kFinite); test_floatclass(reporter, -max, kFinite); test_floatclass(reporter, inf, kInfinite); test_floatclass(reporter, -inf, kInfinite); test_floatclass(reporter, nan, kNaN); test_floatclass(reporter, -nan, kNaN); const Rec data[] = { { 0, true }, { 1, true }, { -1, true }, { max * 0.75f, true }, { max, true }, { -max * 0.75f, true }, { -max, true }, { inf, false }, { -inf, false }, { nan, false }, }; const IsFiniteProc1 gProc1[] = { isFinite_int, isFinite_float, isFinite_mulzero }; const IsFiniteProc2 gProc2[] = { isFinite2_and, isFinite2_mulzeroadd }; size_t i, n = SK_ARRAY_COUNT(data); for (i = 0; i < n; ++i) { for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) { const Rec& rec = data[i]; bool finite = gProc1[k](rec.fValue); REPORTER_ASSERT(reporter, rec.fIsFinite == finite); } } for (i = 0; i < n; ++i) { const Rec& rec0 = data[i]; for (size_t j = 0; j < n; ++j) { const Rec& rec1 = data[j]; for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) { IsFiniteProc1 proc1 = gProc1[k]; for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) { bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1); bool finite2 = rec0.fIsFinite && rec1.fIsFinite; REPORTER_ASSERT(reporter, finite2 == finite); } } } } test_isRectFinite(reporter); }
virtual void onDrawContent(SkCanvas* canvas) { struct FillAndName { SkPath::FillType fFill; const char* fName; }; static const FillAndName gFills[] = { {SkPath::kWinding_FillType, "Winding"}, {SkPath::kEvenOdd_FillType, "Even / Odd"}, {SkPath::kInverseWinding_FillType, "Inverse Winding"}, {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, }; struct StyleAndName { SkPaint::Style fStyle; const char* fName; }; static const StyleAndName gStyles[] = { {SkPaint::kFill_Style, "Fill"}, {SkPaint::kStroke_Style, "Stroke"}, {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, }; SkPaint titlePaint; titlePaint.setColor(SK_ColorBLACK); titlePaint.setAntiAlias(true); titlePaint.setLCDRenderText(true); titlePaint.setTextSize(24 * SK_Scalar1); const char title[] = "Empty Paths Drawn Into Rectangle Clips With Indicated Style and Fill"; canvas->drawText(title, strlen(title), 40 * SK_Scalar1, 100*SK_Scalar1, titlePaint); SkRandom rand; SkRect rect = SkRect::MakeWH(125*SK_Scalar1, 100*SK_Scalar1); int i = 0; canvas->save(); canvas->translate(80 * SK_Scalar1, 0); canvas->save(); for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { if (0 == i % 4) { canvas->restore(); canvas->translate(0, rect.height() + 50 * SK_Scalar1); canvas->save(); } else { canvas->translate(rect.width() + 100 * SK_Scalar1, 0); } ++i; SkColor color = rand.nextU(); color = 0xff000000| color; // force solid this->drawEmpty(canvas, color, rect, gStyles[style].fStyle, gFills[fill].fFill); SkPaint rectPaint; rectPaint.setColor(SK_ColorBLACK); rectPaint.setStyle(SkPaint::kStroke_Style); rectPaint.setStrokeWidth(-1); rectPaint.setAntiAlias(true); canvas->drawRect(rect, rectPaint); char label[1024]; sprintf(label, "%s, %s", gStyles[style].fName, gFills[fill].fName); SkPaint labelPaint; labelPaint.setColor(color); labelPaint.setAntiAlias(true); labelPaint.setLCDRenderText(true); canvas->drawText(label, strlen(label), 0, rect.height() + 15 * SK_Scalar1, labelPaint); } } canvas->restore(); canvas->restore(); }
gTimesNewRoman_Italic, -1}, {"Times", SkTypeface::kBoldItalic, "Times New Roman", "Times New Roman Bold Italic.ttf", gTimesNewRoman_BoldItalic, -1}, {"Times New Roman", SkTypeface::kNormal, "Times New Roman", "Times New Roman.ttf", gTimesNewRoman, -1}, {"Times New Roman", SkTypeface::kBold, "Times New Roman", "Times New Roman Bold.ttf", gTimesNewRoman_Bold, -1}, {"Times New Roman", SkTypeface::kItalic, "Times New Roman", "Times New Roman Italic.ttf", gTimesNewRoman_Italic, -1}, {"Times New Roman", SkTypeface::kBoldItalic, "Times New Roman", "Times New Roman Bold Italic.ttf", gTimesNewRoman_BoldItalic, -1}, {"Times Roman", SkTypeface::kNormal, "Liberation Sans", "LiberationSans-Regular.ttf", gLiberationSans, -1}, }; const int gFontsCount = (int) SK_ARRAY_COUNT(gFonts); const char* gStyleName[] = { "kNormal", "kBold", "kItalic", "kBoldItalic", }; const char gHeader[] = "/*\n" " * Copyright 2014 Google Inc.\n" " *\n" " * Use of this source code is governed by a BSD-style license that can be\n" " * found in the LICENSE file.\n" " */\n"
static void testop() { for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { testop(gRec[i].r0, gRec[i].r1, gRec[i].op, gRec[i].expectedR); } }
int tool_main(int argc, char** argv) { SkGraphics::Init(); if (argc < 3) { usage(); return -1; } SkString inFile, outFile, inDir, outDir; char* const* stop = argv + argc; for (++argv; argv < stop; ++argv) { if (strcmp(*argv, "-i") == 0) { argv++; if (argv < stop && **argv) { inFile.set(*argv); } else { SkDebugf("missing arg for -i\n"); usage(); return -1; } } else if (strcmp(*argv, "--input-dir") == 0) { argv++; if (argv < stop && **argv) { inDir.set(*argv); } else { SkDebugf("missing arg for --input-dir\n"); usage(); return -1; } } else if (strcmp(*argv, "--output-dir") == 0) { argv++; if (argv < stop && **argv) { outDir.set(*argv); } else { SkDebugf("missing arg for --output-dir\n"); usage(); return -1; } } else if (strcmp(*argv, "-o") == 0) { argv++; if (argv < stop && **argv) { outFile.set(*argv); } else { SkDebugf("missing arg for -o\n"); usage(); return -1; } } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { usage(); return 0; } else { SkDebugf("unknown arg %s\n", *argv); usage(); return -1; } } SkOSFile::Iter iter(inDir.c_str(), "skp"); SkString inputFilename, outputFilename; if (iter.next(&inputFilename)) { do { inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str()); if (!outDir.isEmpty()) { outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str()); } SkDebugf("Executing %s\n", inputFilename.c_str()); filter_picture(inFile, outFile); } while(iter.next(&inputFilename)); } else if (!inFile.isEmpty()) { filter_picture(inFile, outFile); } else { usage(); return -1; } for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied); } SkGraphics::Term(); return 0; }
// Test out the non-degenerate RR cases static void test_round_rect_general(skiatest::Reporter* reporter) { static const SkScalar kEps = 0.1f; static const SkScalar kDist20 = 20 * (SK_Scalar1 - SK_ScalarRoot2Over2); static const SkPoint pts[] = { // Upper Left { kDist20 - kEps, kDist20 - kEps }, // out { kDist20 + kEps, kDist20 + kEps }, // in // Upper Right { kWidth + kEps - kDist20, kDist20 - kEps }, // out { kWidth - kEps - kDist20, kDist20 + kEps }, // in // Lower Right { kWidth + kEps - kDist20, kHeight + kEps - kDist20 }, // out { kWidth - kEps - kDist20, kHeight - kEps - kDist20 }, // in // Lower Left { kDist20 - kEps, kHeight + kEps - kDist20 }, //out { kDist20 + kEps, kHeight - kEps - kDist20 }, // in // Middle { SkIntToScalar(50), SkIntToScalar(50) } // in }; static const bool isIn[] = { false, true, false, true, false, true, false, true, true }; SkASSERT(SK_ARRAY_COUNT(pts) == SK_ARRAY_COUNT(isIn)); //---- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); SkRRect rr1; rr1.setRectXY(rect, 20, 20); REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type()); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr1.contains(pts[i].fX, pts[i].fY)); } //---- static const SkScalar kDist50 = 50*(SK_Scalar1 - SK_ScalarRoot2Over2); static const SkPoint pts2[] = { // Upper Left { -SK_Scalar1, -SK_Scalar1 }, // out { SK_Scalar1, SK_Scalar1 }, // in // Upper Right { kWidth + kEps - kDist20, kDist20 - kEps }, // out { kWidth - kEps - kDist20, kDist20 + kEps }, // in // Lower Right { kWidth + kEps - kDist50, kHeight + kEps - kDist50 }, // out { kWidth - kEps - kDist50, kHeight - kEps - kDist50 }, // in // Lower Left { kDist20 - kEps, kHeight + kEps - kDist50 }, // out { kDist20 + kEps, kHeight - kEps - kDist50 }, // in // Middle { SkIntToScalar(50), SkIntToScalar(50) } // in }; SkASSERT(SK_ARRAY_COUNT(pts2) == SK_ARRAY_COUNT(isIn)); SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } }; SkRRect rr2; rr2.setRectRadii(rect, radii); REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type()); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr2.contains(pts2[i].fX, pts2[i].fY)); } }
// Exercise the RR's contains rect method static void test_round_rect_contains_rect(skiatest::Reporter* reporter) { static const int kNumRRects = 4; static const SkVector gRadii[kNumRRects][4] = { { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // rect { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } }, // circle { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } }, // simple { { 0, 0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } } // complex }; SkRRect rrects[kNumRRects]; for (int i = 0; i < kNumRRects; ++i) { rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]); } // First test easy outs - boxes that are obviously out on // each corner and edge static const SkRect easyOuts[] = { { -5, -5, 5, 5 }, // NW { 15, -5, 20, 5 }, // N { 35, -5, 45, 5 }, // NE { 35, 15, 45, 20 }, // E { 35, 45, 35, 45 }, // SE { 15, 35, 20, 45 }, // S { -5, 35, 5, 45 }, // SW { -5, 15, 5, 20 } // W }; for (int i = 0; i < kNumRRects; ++i) { for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) { REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j])); } } // Now test non-trivial containment. For each compass // point walk a 1x1 rect in from the edge of the bounding // rect static const int kNumSteps = 15; bool answers[kNumRRects][8][kNumSteps] = { // all the test rects are inside the degenerate rrect { // rect { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }, // for the circle we expect 6 blocks to be out on the // corners (then the rest in) and only the first block // out on the vertical and horizontal axes (then // the rest in) { // circle { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }, // for the simple round rect we expect 3 out on // the corners (then the rest in) and no blocks out // on the vertical and horizontal axes { // simple RR { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }, // for the complex case the answer is different for each direction { // complex RR // all in for NW (rect) corner (same as rect case) { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // only first block out for N (same as circle case) { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // first 6 blocks out for NE (same as circle case) { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // only first block out for E (same as circle case) { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // first 3 blocks out for SE (same as simple case) { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // first two blocks out for S { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // first 9 blocks out for SW { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 }, // first two blocks out for W (same as S) { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, } }; for (int i = 0; i < kNumRRects; ++i) { test_direction(reporter, rrects[i], 0, 1, 0, 1, kNumSteps, answers[i][0]); // NW test_direction(reporter, rrects[i], 19.5f, 0, 0, 1, kNumSteps, answers[i][1]); // N test_direction(reporter, rrects[i], 40, -1, 0, 1, kNumSteps, answers[i][2]); // NE test_direction(reporter, rrects[i], 40, -1, 19.5f, 0, kNumSteps, answers[i][3]); // E test_direction(reporter, rrects[i], 40, -1, 40, -1, kNumSteps, answers[i][4]); // SE test_direction(reporter, rrects[i], 19.5f, 0, 40, -1, kNumSteps, answers[i][5]); // S test_direction(reporter, rrects[i], 0, 1, 40, -1, kNumSteps, answers[i][6]); // SW test_direction(reporter, rrects[i], 0, 1, 19.5f, 0, kNumSteps, answers[i][7]); // W } }
void onOnceBeforeDraw() override { SkTextBlobBuilder builder; // LCD SkPaint paint; paint.setTextSize(32); const char* text = "The quick brown fox jumps over the lazy dog"; paint.setSubpixelText(true); paint.setLCDRenderText(true); paint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint); add_to_text_blob(&builder, text, paint, 0, 0); fBlob.reset(builder.build()); // create a looper which sandwhiches an effect in two normal draws LooperSettings looperSandwhich[] = { { SkXfermode::kSrc_Mode, SK_ColorMAGENTA, SkPaint::kFill_Style, 0, 0, 0, false }, { SkXfermode::kSrcOver_Mode, 0x88000000, SkPaint::kFill_Style, 0, 10.f, 0, true }, { SkXfermode::kSrcOver_Mode, 0x50FF00FF, SkPaint::kFill_Style, 0, 20.f, 0, false }, }; LooperSettings compound[] = { { SkXfermode::kSrc_Mode, SK_ColorWHITE, SkPaint::kStroke_Style, 1.f * 3/4, 0, 0, false }, { SkXfermode::kSrc_Mode, SK_ColorRED, SkPaint::kStroke_Style, 4.f, 0, 0, false }, { SkXfermode::kSrc_Mode, SK_ColorBLUE, SkPaint::kFill_Style, 0, 0, 0, false }, { SkXfermode::kSrcOver_Mode, 0x88000000, SkPaint::kFill_Style, 0, 10.f, 0, true } }; LooperSettings xfermode[] = { { SkXfermode::kDifference_Mode, SK_ColorWHITE, SkPaint::kFill_Style, 0, 0, 0, false }, { SkXfermode::kSrcOver_Mode, 0xFF000000, SkPaint::kFill_Style, 0, 1.f, 0, true }, { SkXfermode::kSrcOver_Mode, 0x50FF00FF, SkPaint::kFill_Style, 0, 2.f, 0, false }, }; // NOTE, this should be ignored by textblobs LooperSettings skew[] = { { SkXfermode::kSrc_Mode, SK_ColorRED, SkPaint::kFill_Style, 0, 0, -1.f, false }, { SkXfermode::kSrc_Mode, SK_ColorGREEN, SkPaint::kFill_Style, 0, 10.f, -1.f, false }, { SkXfermode::kSrc_Mode, SK_ColorBLUE, SkPaint::kFill_Style, 0, 20.f, -1.f, false }, }; LooperSettings kitchenSink[] = { { SkXfermode::kSrc_Mode, SK_ColorWHITE, SkPaint::kStroke_Style, 1.f * 3/4, 0, 0, false }, { SkXfermode::kSrc_Mode, SK_ColorBLACK, SkPaint::kFill_Style, 0, 0, 0, false }, { SkXfermode::kDifference_Mode, SK_ColorWHITE, SkPaint::kFill_Style, 1.f, 10.f, 0, false }, { SkXfermode::kSrc_Mode, SK_ColorWHITE, SkPaint::kFill_Style, 0, 10.f, 0, true }, { SkXfermode::kSrcOver_Mode, 0x50FF00FF, SkPaint::kFill_Style, 0, 20.f, 0, false }, }; fLoopers.push_back().reset(setupLooper(SkLayerDrawLooper::kMaskFilter_Bit | SkLayerDrawLooper::kXfermode_Bit | SkLayerDrawLooper::kStyle_Bit, &mask_filter, compound, SK_ARRAY_COUNT(compound))); fLoopers.push_back().reset(setupLooper(SkLayerDrawLooper::kPathEffect_Bit | SkLayerDrawLooper::kXfermode_Bit, &path_effect, looperSandwhich, SK_ARRAY_COUNT(looperSandwhich))); fLoopers.push_back().reset(setupLooper(SkLayerDrawLooper::kShader_Bit | SkLayerDrawLooper::kColorFilter_Bit | SkLayerDrawLooper::kXfermode_Bit, &color_filter, looperSandwhich, SK_ARRAY_COUNT(looperSandwhich))); fLoopers.push_back().reset(setupLooper(SkLayerDrawLooper::kShader_Bit | SkLayerDrawLooper::kColorFilter_Bit | SkLayerDrawLooper::kXfermode_Bit, &color_filter, xfermode, SK_ARRAY_COUNT(xfermode))); fLoopers.push_back().reset(setupLooper(0, nullptr, skew, SK_ARRAY_COUNT(skew))); fLoopers.push_back().reset(setupLooper(SkLayerDrawLooper::kMaskFilter_Bit | SkLayerDrawLooper::kShader_Bit | SkLayerDrawLooper::kColorFilter_Bit | SkLayerDrawLooper::kPathEffect_Bit | SkLayerDrawLooper::kStyle_Bit | SkLayerDrawLooper::kXfermode_Bit, &kitchen_sink, kitchenSink, SK_ARRAY_COUNT(kitchenSink))); // Test we respect overrides fLoopers.push_back().reset(setupLooper(0, &kitchen_sink, kitchenSink, SK_ARRAY_COUNT(kitchenSink))); }
// Test out the cases when the RR degenerates to a rect static void test_round_rect_rects(skiatest::Reporter* reporter) { SkRect r; static const SkPoint pts[] = { // Upper Left { -SK_Scalar1, -SK_Scalar1 }, // out { SK_Scalar1, SK_Scalar1 }, // in // Upper Right { SkIntToScalar(101), -SK_Scalar1}, // out { SkIntToScalar(99), SK_Scalar1 }, // in // Lower Right { SkIntToScalar(101), SkIntToScalar(101) }, // out { SkIntToScalar(99), SkIntToScalar(99) }, // in // Lower Left { -SK_Scalar1, SkIntToScalar(101) }, // out { SK_Scalar1, SkIntToScalar(99) }, // in // Middle { SkIntToScalar(50), SkIntToScalar(50) } // in }; static const bool isIn[] = { false, true, false, true, false, true, false, true, true }; SkASSERT(SK_ARRAY_COUNT(pts) == SK_ARRAY_COUNT(isIn)); //---- SkRRect empty; empty.setEmpty(); REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type()); r = empty.rect(); REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom); //---- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); SkRRect rr1; rr1.setRectXY(rect, 0, 0); REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type()); r = rr1.rect(); REPORTER_ASSERT(reporter, rect == r); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr1.contains(pts[i].fX, pts[i].fY)); } //---- SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; SkRRect rr2; rr2.setRectRadii(rect, radii); REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type()); r = rr2.rect(); REPORTER_ASSERT(reporter, rect == r); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr2.contains(pts[i].fX, pts[i].fY)); } //---- SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } }; SkRRect rr3; rr3.setRectRadii(rect, radii2); REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type()); }
void GrGLGetDriverInfo(GrGLStandard standard, GrGLVendor vendor, const char* rendererString, const char* versionString, GrGLDriver* outDriver, GrGLDriverVersion* outVersion) { int major, minor, rev, driverMajor, driverMinor; *outDriver = kUnknown_GrGLDriver; *outVersion = GR_GL_DRIVER_UNKNOWN_VER; // These null checks are for test GL contexts that return nullptr in their // glGetString implementation. if (!rendererString) { rendererString = ""; } if (!versionString) { versionString = ""; } static const char kChromium[] = "Chromium"; char suffix[SK_ARRAY_COUNT(kChromium)]; if (0 == strcmp(rendererString, kChromium) || (3 == sscanf(versionString, "OpenGL ES %d.%d %8s", &major, &minor, suffix) && 0 == strcmp(kChromium, suffix))) { *outDriver = kChromium_GrGLDriver; return; } if (standard == kGL_GrGLStandard) { if (kNVIDIA_GrGLVendor == vendor) { *outDriver = kNVIDIA_GrGLDriver; int n = sscanf(versionString, "%d.%d.%d NVIDIA %d.%d", &major, &minor, &rev, &driverMajor, &driverMinor); // Some older NVIDIA drivers don't report the driver version. if (5 == n) { *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); } return; } int n = sscanf(versionString, "%d.%d Mesa %d.%d", &major, &minor, &driverMajor, &driverMinor); if (4 == n) { *outDriver = kMesa_GrGLDriver; *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); return; } } else { if (kNVIDIA_GrGLVendor == vendor) { *outDriver = kNVIDIA_GrGLDriver; int n = sscanf(versionString, "OpenGL ES %d.%d NVIDIA %d.%d", &major, &minor, &driverMajor, &driverMinor); // Some older NVIDIA drivers don't report the driver version. if (4 == n) { *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); } return; } int n = sscanf(versionString, "OpenGL ES %d.%d Mesa %d.%d", &major, &minor, &driverMajor, &driverMinor); if (4 == n) { *outDriver = kMesa_GrGLDriver; *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); return; } if (0 == strncmp("ANGLE", rendererString, 5)) { *outDriver = kANGLE_GrGLDriver; n = sscanf(versionString, "OpenGL ES %d.%d (ANGLE %d.%d", &major, &minor, &driverMajor, &driverMinor); if (4 == n) { *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); } return; } } if (kIntel_GrGLVendor == vendor) { // We presume we're on the Intel driver since it hasn't identified itself as Mesa. *outDriver = kIntel_GrGLDriver; } if (kQualcomm_GrGLVendor == vendor) { *outDriver = kQualcomm_GrGLDriver; int n = sscanf(versionString, "OpenGL ES %d.%d V@%d.%d", &major, &minor, &driverMajor, &driverMinor); if (4 == n) { *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); } return; } }
GrGLRenderer GrGLGetRendererFromString(const char* rendererString) { if (rendererString) { if (0 == strcmp(rendererString, "NVIDIA Tegra 3")) { return kTegra3_GrGLRenderer; } else if (0 == strcmp(rendererString, "NVIDIA Tegra")) { return kTegra2_GrGLRenderer; } int lastDigit; int n = sscanf(rendererString, "PowerVR SGX 54%d", &lastDigit); if (1 == n && lastDigit >= 0 && lastDigit <= 9) { return kPowerVR54x_GrGLRenderer; } // certain iOS devices also use PowerVR54x GPUs static const char kAppleA4Str[] = "Apple A4"; static const char kAppleA5Str[] = "Apple A5"; static const char kAppleA6Str[] = "Apple A6"; if (0 == strncmp(rendererString, kAppleA4Str, SK_ARRAY_COUNT(kAppleA4Str)-1) || 0 == strncmp(rendererString, kAppleA5Str, SK_ARRAY_COUNT(kAppleA5Str)-1) || 0 == strncmp(rendererString, kAppleA6Str, SK_ARRAY_COUNT(kAppleA6Str)-1)) { return kPowerVR54x_GrGLRenderer; } static const char kPowerVRRogueStr[] = "PowerVR Rogue"; static const char kAppleA7Str[] = "Apple A7"; static const char kAppleA8Str[] = "Apple A8"; if (0 == strncmp(rendererString, kPowerVRRogueStr, SK_ARRAY_COUNT(kPowerVRRogueStr)-1) || 0 == strncmp(rendererString, kAppleA7Str, SK_ARRAY_COUNT(kAppleA7Str)-1) || 0 == strncmp(rendererString, kAppleA8Str, SK_ARRAY_COUNT(kAppleA8Str)-1)) { return kPowerVRRogue_GrGLRenderer; } int adrenoNumber; n = sscanf(rendererString, "Adreno (TM) %d", &adrenoNumber); if (1 == n) { if (adrenoNumber >= 300) { if (adrenoNumber < 400) { return kAdreno3xx_GrGLRenderer; } if (adrenoNumber < 500) { return kAdreno4xx_GrGLRenderer; } if (adrenoNumber < 600) { return kAdreno5xx_GrGLRenderer; } } } int intelNumber; n = sscanf(rendererString, "Intel(R) Iris(TM) Graphics %d", &intelNumber); if (1 != n) { n = sscanf(rendererString, "Intel(R) HD Graphics %d", &intelNumber); } if (1 == n) { if (intelNumber >= 6000 && intelNumber < 7000) { return kIntel6xxx_GrGLRenderer; } } if (0 == strcmp("Mesa Offscreen", rendererString)) { return kOSMesa_GrGLRenderer; } static const char kMaliTStr[] = "Mali-T"; if (0 == strncmp(rendererString, kMaliTStr, SK_ARRAY_COUNT(kMaliTStr) - 1)) { return kMaliT_GrGLRenderer; } static const char kANGLEStr[] = "ANGLE"; if (0 == strncmp(rendererString, kANGLEStr, SK_ARRAY_COUNT(kANGLEStr) - 1)) { return kANGLE_GrGLRenderer; } } return kOther_GrGLRenderer; }
DEF_TEST(MetaData, reporter) { SkMetaData m1; REPORTER_ASSERT(reporter, !m1.findS32("int")); REPORTER_ASSERT(reporter, !m1.findScalar("scalar")); REPORTER_ASSERT(reporter, !m1.findString("hello")); REPORTER_ASSERT(reporter, !m1.removeS32("int")); REPORTER_ASSERT(reporter, !m1.removeScalar("scalar")); REPORTER_ASSERT(reporter, !m1.removeString("hello")); REPORTER_ASSERT(reporter, !m1.removeString("true")); REPORTER_ASSERT(reporter, !m1.removeString("false")); m1.setS32("int", 12345); m1.setScalar("scalar", SK_Scalar1 * 42); m1.setString("hello", "world"); m1.setPtr("ptr", &m1); m1.setBool("true", true); m1.setBool("false", false); int32_t n; SkScalar s; m1.setScalar("scalar", SK_Scalar1/2); REPORTER_ASSERT(reporter, m1.findS32("int", &n) && n == 12345); REPORTER_ASSERT(reporter, m1.findScalar("scalar", &s) && s == SK_Scalar1/2); REPORTER_ASSERT(reporter, !strcmp(m1.findString("hello"), "world")); REPORTER_ASSERT(reporter, m1.hasBool("true", true)); REPORTER_ASSERT(reporter, m1.hasBool("false", false)); SkMetaData::Iter iter(m1); const char* name; static const struct { const char* fName; SkMetaData::Type fType; int fCount; } gElems[] = { { "int", SkMetaData::kS32_Type, 1 }, { "scalar", SkMetaData::kScalar_Type, 1 }, { "ptr", SkMetaData::kPtr_Type, 1 }, { "hello", SkMetaData::kString_Type, sizeof("world") }, { "true", SkMetaData::kBool_Type, 1 }, { "false", SkMetaData::kBool_Type, 1 } }; int loop = 0; int count; SkMetaData::Type t; while ((name = iter.next(&t, &count)) != nullptr) { int match = 0; for (unsigned i = 0; i < SK_ARRAY_COUNT(gElems); i++) { if (!strcmp(name, gElems[i].fName)) { match += 1; REPORTER_ASSERT(reporter, gElems[i].fType == t); REPORTER_ASSERT(reporter, gElems[i].fCount == count); } } REPORTER_ASSERT(reporter, match == 1); loop += 1; } REPORTER_ASSERT(reporter, loop == SK_ARRAY_COUNT(gElems)); REPORTER_ASSERT(reporter, m1.removeS32("int")); REPORTER_ASSERT(reporter, m1.removeScalar("scalar")); REPORTER_ASSERT(reporter, m1.removeString("hello")); REPORTER_ASSERT(reporter, m1.removeBool("true")); REPORTER_ASSERT(reporter, m1.removeBool("false")); REPORTER_ASSERT(reporter, !m1.findS32("int")); REPORTER_ASSERT(reporter, !m1.findScalar("scalar")); REPORTER_ASSERT(reporter, !m1.findString("hello")); REPORTER_ASSERT(reporter, !m1.findBool("true")); REPORTER_ASSERT(reporter, !m1.findBool("false")); test_ptrs(reporter); }
// Make sure our blits are invariant with the width of the blit (i.e. that // special case for 8 at a time have the same results as narrower blits) static void test_diagonal(skiatest::Reporter* reporter) { static const int W = 64; static const int H = W; static const SkBitmap::Config gDstConfig[] = { SkBitmap::kARGB_8888_Config, SkBitmap::kRGB_565_Config, // SkBitmap::kARGB_4444_Config, // SkBitmap::kA8_Config, }; static const SkColor gDstBG[] = { 0, 0xFFFFFFFF }; SkPaint paint; SkBitmap srcBM; srcBM.setConfig(SkBitmap::kARGB_8888_Config, W, H); srcBM.allocPixels(); SkRect srcR = { 0, 0, SkIntToScalar(srcBM.width()), SkIntToScalar(srcBM.height()) }; // cons up a mesh to draw the bitmap with Mesh mesh(srcBM, &paint); for (size_t i = 0; i < SK_ARRAY_COUNT(gDstConfig); i++) { SkBitmap dstBM0, dstBM1; dstBM0.setConfig(gDstConfig[i], W, H); dstBM1.setConfig(gDstConfig[i], W, H); dstBM0.allocPixels(); dstBM1.allocPixels(); SkCanvas canvas0(dstBM0); SkCanvas canvas1(dstBM1); SkColor bgColor; for (size_t j = 0; j < SK_ARRAY_COUNT(gDstBG); j++) { bgColor = gDstBG[j]; for (int c = 0; c <= 0xFF; c++) { srcBM.eraseARGB(0xFF, c, c, c); for (int k = 0; k < 4; k++) { bool dither = (k & 1) != 0; uint8_t alpha = (k & 2) ? 0x80 : 0xFF; paint.setDither(dither); paint.setAlpha(alpha); dstBM0.eraseColor(bgColor); dstBM1.eraseColor(bgColor); canvas0.drawRect(srcR, paint); mesh.draw(&canvas1, &paint); if (!gOnce && false) { save_bm(dstBM0, "drawBitmap.png"); save_bm(dstBM1, "drawMesh.png"); gOnce = true; } if (memcmp(dstBM0.getPixels(), dstBM1.getPixels(), dstBM0.getSize())) { SkString str; str.printf("Diagonal config=%s bg=0x%x dither=%d alpha=0x%x src=0x%x", gConfigName[gDstConfig[i]], bgColor, dither, alpha, c); reporter->reportFailed(str); } } } } } }
{ SkType_FillType, "winding|evenOdd" }, { SkType_FilterType, "none|bilinear" }, { SkType_FontStyle, "normal|bold|italic|boldItalic" }, { SkType_FromPathMode, "normal|angle|position" }, { SkType_Join, "miter|round|blunt" }, { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, { SkType_PathDirection, "cw|ccw" }, { SkType_Style, "fill|stroke|strokeAndFill" }, { SkType_TextBoxAlign, "start|center|end" }, { SkType_TextBoxMode, "oneLine|lineBreak" }, { SkType_TileMode, "clamp|repeat|mirror" }, { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" "srcATop|dstATop|xor|darken|lighten" }, }; static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); SkAnimatorScript::SkAnimatorScript(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) : SkScriptEngine(SkScriptEngine::ToOpType(type)), fMaker(maker), fParent(NULL), fWorking(working) { memberCallBack(EvalMember, (void*) this); memberFunctionCallBack(EvalMemberFunction, (void*) this); boxCallBack(Box, (void*) this); unboxCallBack(Unbox, (void*) &maker); propertyCallBack(EvalID, (void*) this); // must be first (entries are prepended, will be last), since it never fails propertyCallBack(Infinity, (void*) this); propertyCallBack(NaN, (void*) this); functionCallBack(Eval, (void*) this); functionCallBack(IsFinite, (void*) this); functionCallBack(IsNaN, (void*) this); if (type == SkType_ARGB) {
SkString GrDrawTargetCaps::dump() const { SkString r; static const char* gNY[] = {"NO", "YES"}; r.appendf("MIP Map Support : %s\n", gNY[fMipMapSupport]); r.appendf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]); r.appendf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]); r.appendf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]); r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); r.appendf("Discard Render Target Support : %s\n", gNY[fDiscardRenderTargetSupport]); r.appendf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); r.appendf("Gpu Tracing Support : %s\n", gNY[fGpuTracingSupport]); r.appendf("Compressed Update Support : %s\n", gNY[fCompressedTexSubImageSupport]); r.appendf("Oversized Stencil Support : %s\n", gNY[fOversizedStencilSupport]); r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]); r.appendf("Max Texture Size : %d\n", fMaxTextureSize); r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize); r.appendf("Max Sample Count : %d\n", fMaxSampleCount); r.appendf("Map Buffer Support : %s\n", map_flags_to_string(fMapBufferFlags).c_str()); static const char* kConfigNames[] = { "Unknown", // kUnknown_GrPixelConfig "Alpha8", // kAlpha_8_GrPixelConfig, "Index8", // kIndex_8_GrPixelConfig, "RGB565", // kRGB_565_GrPixelConfig, "RGBA444", // kRGBA_4444_GrPixelConfig, "RGBA8888", // kRGBA_8888_GrPixelConfig, "BGRA8888", // kBGRA_8888_GrPixelConfig, "SRGBA8888",// kSRGBA_8888_GrPixelConfig, "ETC1", // kETC1_GrPixelConfig, "LATC", // kLATC_GrPixelConfig, "R11EAC", // kR11_EAC_GrPixelConfig, "ASTC12x12",// kASTC_12x12_GrPixelConfig, "RGBAFloat",// kRGBA_float_GrPixelConfig "AlphaHalf",// kAlpha_half_GrPixelConfig }; GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); GR_STATIC_ASSERT(7 == kSRGBA_8888_GrPixelConfig); GR_STATIC_ASSERT(8 == kETC1_GrPixelConfig); GR_STATIC_ASSERT(9 == kLATC_GrPixelConfig); GR_STATIC_ASSERT(10 == kR11_EAC_GrPixelConfig); GR_STATIC_ASSERT(11 == kASTC_12x12_GrPixelConfig); GR_STATIC_ASSERT(12 == kRGBA_float_GrPixelConfig); GR_STATIC_ASSERT(13 == kAlpha_half_GrPixelConfig); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is renderable: %s, with MSAA: %s\n", kConfigNames[i], gNY[fConfigRenderSupport[i][0]], gNY[fConfigRenderSupport[i][1]]); } SkASSERT(!fConfigTextureSupport[kUnknown_GrPixelConfig]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is uploadable to a texture: %s\n", kConfigNames[i], gNY[fConfigTextureSupport[i]]); } r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]); for (int s = 0; s < kGrShaderTypeCount; ++s) { GrShaderType shaderType = static_cast<GrShaderType>(s); r.appendf("\t%s:\n", shader_type_to_string(shaderType)); for (int p = 0; p < kGrSLPrecisionCount; ++p) { if (fFloatPrecisions[s][p].supported()) { GrSLPrecision precision = static_cast<GrSLPrecision>(p); r.appendf("\t\t%s: log_low: %d log_high: %d bits: %d\n", precision_to_string(precision), fFloatPrecisions[s][p].fLogRangeLow, fFloatPrecisions[s][p].fLogRangeHigh, fFloatPrecisions[s][p].fBits); } } } return r; }
#define PATH_SLASH "/" #define IN_DIR "/usr/local/google/home/caryclark" PATH_SLASH "9-30-13-skp" #define OUT_DIR "/media/01CD75512A7F9EE0/4" PATH_SLASH #define LINE_FEED "\n" #endif #define PATH_STR_SIZE 512 static const struct { int directory; const char* filename; } skipOverSkGr[] = { {1, "http___accuweather_com_.skp"}, // Couldn't convert bitmap to texture.http___absoku072_com_ }; static const size_t skipOverSkGrCount = SK_ARRAY_COUNT(skipOverSkGr); ///////////////////////////////////////// class SkpSkGrThreadedRunnable; enum TestStep { kCompareBits, kEncodeFiles, }; enum { kMaxLength = 128, kMaxFiles = 128, };
static int filter_picture(const SkString& inFile, const SkString& outFile) { SkAutoTUnref<SkPicture> inPicture; SkFILEStream inStream(inFile.c_str()); if (inStream.isValid()) { inPicture.reset(SkPicture::CreateFromStream(&inStream)); } if (nullptr == inPicture.get()) { SkDebugf("Could not read file %s\n", inFile.c_str()); return -1; } int localCount[SK_ARRAY_COUNT(gOptTable)]; memset(localCount, 0, sizeof(localCount)); SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), SkScalarCeilToInt(inPicture->cullRect().height())); inPicture->playback(&debugCanvas); // delete the initial save and restore since replaying the commands will // re-add them if (debugCanvas.getSize() > 1) { debugCanvas.deleteDrawCommandAt(0); debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1); } bool changed = true; int numBefore = debugCanvas.getSize(); while (changed) { changed = false; for (int i = 0; i < debugCanvas.getSize(); ++i) { for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) { (*gOptTable[opt].fApply)(&debugCanvas, i); ++gOptTable[opt].fNumTimesApplied; ++localCount[opt]; if (debugCanvas.getSize() == i) { // the optimization removed all the remaining operations break; } opt = 0; // try all the opts all over again changed = true; } } } } int numAfter = debugCanvas.getSize(); if (!outFile.isEmpty()) { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width(), inPicture->cullRect().height(), nullptr, 0); debugCanvas.draw(canvas); SkAutoTUnref<SkPicture> outPicture(recorder.endRecording()); SkFILEWStream outStream(outFile.c_str()); outPicture->serialize(&outStream); } bool someOptFired = false; for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { if (0 != localCount[opt]) { SkDebugf("%d: %d ", opt, localCount[opt]); someOptFired = true; } } if (!someOptFired) { SkDebugf("No opts fired\n"); } else { SkDebugf("\t before: %d after: %d delta: %d\n", numBefore, numAfter, numBefore-numAfter); } return 0; }
SkString GrDrawTargetCaps::dump() const { SkString r; static const char* gNY[] = {"NO", "YES"}; r.appendf("MIP Map Support : %s\n", gNY[fMipMapSupport]); r.appendf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]); r.appendf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]); r.appendf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]); r.appendf("HW AA Lines Support : %s\n", gNY[fHWAALineSupport]); r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); r.appendf("Discard Render Target Support: %s\n", gNY[fDiscardRenderTargetSupport]); r.appendf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); r.appendf("Gpu Tracing Support : %s\n", gNY[fGpuTracingSupport]); r.appendf("Compressed Update Support : %s\n", gNY[fCompressedTexSubImageSupport]); r.appendf("Max Texture Size : %d\n", fMaxTextureSize); r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize); r.appendf("Max Sample Count : %d\n", fMaxSampleCount); r.appendf("Map Buffer Support : %s\n", map_flags_to_string(fMapBufferFlags).c_str()); static const char* kConfigNames[] = { "Unknown", // kUnknown_GrPixelConfig "Alpha8", // kAlpha_8_GrPixelConfig, "Index8", // kIndex_8_GrPixelConfig, "RGB565", // kRGB_565_GrPixelConfig, "RGBA444", // kRGBA_4444_GrPixelConfig, "RGBA8888", // kRGBA_8888_GrPixelConfig, "BGRA8888", // kBGRA_8888_GrPixelConfig, "ETC1", // kETC1_GrPixelConfig, "LATC", // kLATC_GrPixelConfig, "R11EAC", // kR11_EAC_GrPixelConfig, "ASTC12x12",// kASTC_12x12_GrPixelConfig, "RGBAFloat", // kRGBA_float_GrPixelConfig }; GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); GR_STATIC_ASSERT(7 == kETC1_GrPixelConfig); GR_STATIC_ASSERT(8 == kLATC_GrPixelConfig); GR_STATIC_ASSERT(9 == kR11_EAC_GrPixelConfig); GR_STATIC_ASSERT(10 == kASTC_12x12_GrPixelConfig); GR_STATIC_ASSERT(11 == kRGBA_float_GrPixelConfig); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is renderable: %s, with MSAA: %s\n", kConfigNames[i], gNY[fConfigRenderSupport[i][0]], gNY[fConfigRenderSupport[i][1]]); } SkASSERT(!fConfigTextureSupport[kUnknown_GrPixelConfig]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is uploadable to a texture: %s\n", kConfigNames[i], gNY[fConfigTextureSupport[i]]); } return r; }
SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) : INHERITED(desc.fLocalMatrix) { SkASSERT(desc.fCount > 1); fGradFlags = SkToU8(desc.fGradFlags); SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount); SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs)); fTileMode = desc.fTileMode; fTileProc = gTileProcs[desc.fTileMode]; /* Note: we let the caller skip the first and/or last position. i.e. pos[0] = 0.3, pos[1] = 0.7 In these cases, we insert dummy entries to ensure that the final data will be bracketed by [0, 1]. i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1 Thus colorCount (the caller's value, and fColorCount (our value) may differ by up to 2. In the above example: colorCount = 2 fColorCount = 4 */ fColorCount = desc.fCount; // check if we need to add in dummy start and/or end position/colors bool dummyFirst = false; bool dummyLast = false; if (desc.fPos) { dummyFirst = desc.fPos[0] != 0; dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1; fColorCount += dummyFirst + dummyLast; } if (fColorCount > kColorStorageCount) { size_t size = sizeof(SkColor) + sizeof(Rec); if (desc.fPos) { size += sizeof(SkScalar); } fOrigColors = reinterpret_cast<SkColor*>( sk_malloc_throw(size * fColorCount)); } else { fOrigColors = fStorage; } // Now copy over the colors, adding the dummies as needed { SkColor* origColors = fOrigColors; if (dummyFirst) { *origColors++ = desc.fColors[0]; } memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor)); if (dummyLast) { origColors += desc.fCount; *origColors = desc.fColors[desc.fCount - 1]; } } if (desc.fPos && fColorCount) { fOrigPos = (SkScalar*)(fOrigColors + fColorCount); fRecs = (Rec*)(fOrigPos + fColorCount); } else { fOrigPos = NULL; fRecs = (Rec*)(fOrigColors + fColorCount); } if (fColorCount > 2) { Rec* recs = fRecs; recs->fPos = 0; // recs->fScale = 0; // unused; recs += 1; if (desc.fPos) { SkScalar* origPosPtr = fOrigPos; *origPosPtr++ = 0; /* We need to convert the user's array of relative positions into fixed-point positions and scale factors. We need these results to be strictly monotonic (no two values equal or out of order). Hence this complex loop that just jams a zero for the scale value if it sees a segment out of order, and it assures that we start at 0 and end at 1.0 */ SkScalar prev = 0; int startIndex = dummyFirst ? 0 : 1; int count = desc.fCount + dummyLast; for (int i = startIndex; i < count; i++) { // force the last value to be 1.0 SkScalar curr; if (i == desc.fCount) { // we're really at the dummyLast curr = 1; } else { curr = SkScalarPin(desc.fPos[i], 0, 1); } *origPosPtr++ = curr; recs->fPos = SkScalarToFixed(curr); SkFixed diff = SkScalarToFixed(curr - prev); if (diff > 0) { recs->fScale = (1 << 24) / diff; } else { recs->fScale = 0; // ignore this segment } // get ready for the next value prev = curr; recs += 1; } } else { // assume even distribution fOrigPos = NULL; SkFixed dp = SK_Fixed1 / (desc.fCount - 1); SkFixed p = dp; SkFixed scale = (desc.fCount - 1) << 8; // (1 << 24) / dp for (int i = 1; i < desc.fCount - 1; i++) { recs->fPos = p; recs->fScale = scale; recs += 1; p += dp; } recs->fPos = SK_Fixed1; recs->fScale = scale; } } else if (desc.fPos) { SkASSERT(2 == fColorCount); fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1); fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1); if (0 == fOrigPos[0] && 1 == fOrigPos[1]) { fOrigPos = NULL; } } this->initCommon(); }
void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint, const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != NULL); // nothing to draw if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { return; } this->init(paint, skPaint); if (NULL == fDrawTarget) { return; } SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix()); SkGlyphCache* cache = autoCache.getCache(); GrFontScaler* fontScaler = GetGrFontScaler(cache); if (NULL == fStrike) { fStrike = fContext->getFontCache()->getStrike(fontScaler, false); } // transform our starting point { SkPoint loc; fContext->getMatrix().mapXY(x, y, &loc); x = loc.fX; y = loc.fY; } // need to measure first if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { SkVector stop; MeasureText(cache, glyphCacheProc, text, byteLength, &stop); SkScalar stopX = stop.fX; SkScalar stopY = stop.fY; if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { stopX = SkScalarHalf(stopX); stopY = SkScalarHalf(stopY); } x -= stopX; y -= stopY; } const char* stop = text + byteLength; // allocate vertices SkASSERT(NULL == fVertices); bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat(); if (useColorVerts) { fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>( SK_ARRAY_COUNT(gTextVertexWithColorAttribs)); } else { fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( SK_ARRAY_COUNT(gTextVertexAttribs)); } int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs, 0, &fVertices, NULL); GrAlwaysAssert(success); SkAutoKern autokern; SkFixed fxMask = ~0; SkFixed fyMask = ~0; SkFixed halfSampleX, halfSampleY; if (cache->isSubpixel()) { halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix()); if (kX_SkAxisAlignment == baseline) { fyMask = 0; halfSampleY = SK_FixedHalf; } else if (kY_SkAxisAlignment == baseline) { fxMask = 0; halfSampleX = SK_FixedHalf; } } else {
void makePaints() { { // no AA SkPaint p; p.setColor(SK_ColorWHITE); fPaints.push_back(p); } { // AA SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); fPaints.push_back(p); } { // AA with mask filter SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); SkMaskFilter* mf = SkBlurMaskFilter::Create(SkIntToScalar(5), SkBlurMaskFilter::kNormal_BlurStyle, SkBlurMaskFilter::kHighQuality_BlurFlag); p.setMaskFilter(mf)->unref(); fPaints.push_back(p); } { // AA with radial shader SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); SkPoint center = SkPoint::Make(SkIntToScalar(-5), SkIntToScalar(30)); SkColor colors[] = { SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN }; SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 }; SkShader* s = SkGradientShader::CreateRadial(center, SkIntToScalar(20), colors, pos, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode); p.setShader(s)->unref(); fPaints.push_back(p); } { // AA with blur SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); SkBlurDrawLooper* shadowLooper = new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5), SkIntToScalar(10), SK_ColorWHITE, SkBlurDrawLooper::kIgnoreTransform_BlurFlag | SkBlurDrawLooper::kOverrideColor_BlurFlag | SkBlurDrawLooper::kHighQuality_BlurFlag ); SkAutoUnref aurL0(shadowLooper); p.setLooper(shadowLooper); fPaints.push_back(p); } { // AA with stroke style SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(SkIntToScalar(3)); fPaints.push_back(p); } { // AA with stroke style, width = 0 SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); fPaints.push_back(p); } { // AA with stroke and fill style SkPaint p; p.setColor(SK_ColorWHITE); p.setAntiAlias(true); p.setStyle(SkPaint::kStrokeAndFill_Style); p.setStrokeWidth(SkIntToScalar(2)); fPaints.push_back(p); } }
#include "gm.h" #include "SkPath.h" #include "SkDashPathEffect.h" DEF_SIMPLE_GM(bug530095, canvas, 900, 1200) { SkPath path1, path2; path1.addCircle(200, 200, 124); path2.addCircle(2, 2, 1.24f); SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(26); SkScalar intervals[] = {700, 700 }; int intervalCount = (int) SK_ARRAY_COUNT(intervals); paint.setPathEffect(SkDashPathEffect::Create(intervals, intervalCount, -40))->unref(); canvas->drawPath(path1, paint); paint.setStrokeWidth(0.26f); SkScalar smIntervals[] = {7, 7 }; int smIntervalCount = (int) SK_ARRAY_COUNT(smIntervals); paint.setPathEffect(SkDashPathEffect::Create(smIntervals, smIntervalCount, -0.40f))->unref(); canvas->save(); canvas->scale(100, 100); canvas->translate(4, 0); canvas->drawPath(path2, paint); canvas->restore(); paint.setStrokeWidth(26); paint.setPathEffect(SkDashPathEffect::Create(intervals, intervalCount, 0))->unref();
void onDraw(SkCanvas* canvas) override { SkRandom rand(1); canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1); SkRect oval = SkRect::MakeLTRB(-20, -30, 20, 30); const SkScalar kXStart = 60.0f; const SkScalar kYStart = 80.0f; const int kXStep = 150; const int kYStep = 160; int maxX = fMatrices.count(); SkPaint rectPaint; rectPaint.setAntiAlias(true); rectPaint.setStyle(SkPaint::kStroke_Style); rectPaint.setStrokeWidth(SkIntToScalar(0)); rectPaint.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY)); int testCount = 0; for (int i = 0; i < fPaints.count(); ++i) { for (int j = 0; j < fMatrices.count(); ++j) { canvas->save(); SkMatrix mat = fMatrices[j]; // position the oval, and make it at off-integer coords. mat.postTranslate(kXStart + SK_Scalar1 * kXStep * (testCount % maxX) + SK_Scalar1 / 4, kYStart + SK_Scalar1 * kYStep * (testCount / maxX) + 3 * SK_Scalar1 / 4); canvas->concat(mat); SkColor color = genColor(&rand); fPaints[i].setColor(color); canvas->drawRect(oval, rectPaint); canvas->drawOval(oval, fPaints[i]); canvas->restore(); ++testCount; } } // special cases // non-scaled tall and skinny oval for (int i = 0; i < fPaints.count(); ++i) { SkRect oval = SkRect::MakeLTRB(-20, -60, 20, 60); canvas->save(); // position the oval, and make it at off-integer coords. canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.55f + SK_Scalar1 / 4, kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); SkColor color = genColor(&rand); fPaints[i].setColor(color); canvas->drawRect(oval, rectPaint); canvas->drawOval(oval, fPaints[i]); canvas->restore(); } // non-scaled wide and short oval for (int i = 0; i < fPaints.count(); ++i) { SkRect oval = SkRect::MakeLTRB(-80, -30, 80, 30); canvas->save(); // position the oval, and make it at off-integer coords. canvas->translate(kXStart + SK_Scalar1 * kXStep * 4 + SK_Scalar1 / 4, kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + SK_ScalarHalf * kYStep); SkColor color = genColor(&rand); fPaints[i].setColor(color); canvas->drawRect(oval, rectPaint); canvas->drawOval(oval, fPaints[i]); canvas->restore(); } // super skinny oval for (int i = 0; i < fPaints.count(); ++i) { SkRect oval = SkRect::MakeLTRB(0, -60, 1, 60); canvas->save(); // position the oval, and make it at off-integer coords. canvas->translate(kXStart + SK_Scalar1 * kXStep * 3.25f + SK_Scalar1 / 4, kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); SkColor color = genColor(&rand); fPaints[i].setColor(color); canvas->drawOval(oval, fPaints[i]); canvas->restore(); } // super short oval for (int i = 0; i < fPaints.count(); ++i) { SkRect oval = SkRect::MakeLTRB(-80, -1, 80, 0); canvas->save(); // position the oval, and make it at off-integer coords. canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.5f + SK_Scalar1 / 4, kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + SK_ScalarHalf * kYStep); SkColor color = genColor(&rand); fPaints[i].setColor(color); canvas->drawOval(oval, fPaints[i]); canvas->restore(); } // radial gradient SkPoint center = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0)); SkColor colors[] = { SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN }; SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 }; auto shader = SkGradientShader::MakeRadial(center, 20, colors, pos, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode); for (int i = 0; i < fPaints.count(); ++i) { canvas->save(); // position the path, and make it at off-integer coords. canvas->translate(kXStart + SK_Scalar1 * kXStep * 0 + SK_Scalar1 / 4, kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + SK_ScalarHalf * kYStep); SkColor color = genColor(&rand); fPaints[i].setColor(color); fPaints[i].setShader(shader); canvas->drawRect(oval, rectPaint); canvas->drawOval(oval, fPaints[i]); fPaints[i].setShader(nullptr); canvas->restore(); } }
static LONG WINAPI handler(EXCEPTION_POINTERS* e) { const DWORD code = e->ExceptionRecord->ExceptionCode; SkDebugf("\nCaught exception %u", code); for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) { if (kExceptions[i].code == code) { SkDebugf(" %s", kExceptions[i].name); } } SkDebugf("\n"); // We need to run SymInitialize before doing any of the stack walking below. HANDLE hProcess = GetCurrentProcess(); SymInitialize(hProcess, 0, true); STACKFRAME64 frame; sk_bzero(&frame, sizeof(frame)); // Start frame off from the frame that triggered the exception. CONTEXT* c = e->ContextRecord; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Mode = AddrModeFlat; #if defined(_X86_) frame.AddrPC.Offset = c->Eip; frame.AddrStack.Offset = c->Esp; frame.AddrFrame.Offset = c->Ebp; const DWORD machineType = IMAGE_FILE_MACHINE_I386; #elif defined(_AMD64_) frame.AddrPC.Offset = c->Rip; frame.AddrStack.Offset = c->Rsp; frame.AddrFrame.Offset = c->Rbp; const DWORD machineType = IMAGE_FILE_MACHINE_AMD64; #endif while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &frame, c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { // Buffer to store symbol name in. static const int kMaxNameLength = 1024; uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength]; sk_bzero(buffer, sizeof(buffer)); // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in // how much space it can use. IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer); symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); symbol->MaxNameLength = kMaxNameLength - 1; // Translate the current PC into a symbol and byte offset from the symbol. DWORD64 offset; SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol); SkDebugf("%s +%x\n", symbol->Name, offset); } // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). _exit(1); // The compiler wants us to return something. This is what we'd do // if we didn't _exit(). return EXCEPTION_EXECUTE_HANDLER; }
SkString GrGLCaps::dump() const { SkString r = INHERITED::dump(); r.appendf("--- GL-Specific ---\n"); for (int i = 0; i < fStencilFormats.count(); ++i) { r.appendf("Stencil Format %d, stencil bits: %02d, total bits: %02d\n", i, fStencilFormats[i].fStencilBits, fStencilFormats[i].fTotalBits); } static const char* kMSFBOExtStr[] = { "None", "ARB", "EXT", "ES 3.0", "Apple", "IMG MS To Texture", "EXT MS To Texture", }; GR_STATIC_ASSERT(0 == kNone_MSFBOType); GR_STATIC_ASSERT(1 == kDesktop_ARB_MSFBOType); GR_STATIC_ASSERT(2 == kDesktop_EXT_MSFBOType); GR_STATIC_ASSERT(3 == kES_3_0_MSFBOType); GR_STATIC_ASSERT(4 == kES_Apple_MSFBOType); GR_STATIC_ASSERT(5 == kES_IMG_MsToTexture_MSFBOType); GR_STATIC_ASSERT(6 == kES_EXT_MsToTexture_MSFBOType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kMSFBOExtStr) == kLast_MSFBOType + 1); static const char* kFBFetchTypeStr[] = { "None", "EXT", "NV", }; GR_STATIC_ASSERT(0 == kNone_FBFetchType); GR_STATIC_ASSERT(1 == kEXT_FBFetchType); GR_STATIC_ASSERT(2 == kNV_FBFetchType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFBFetchTypeStr) == kLast_FBFetchType + 1); static const char* kInvalidateFBTypeStr[] = { "None", "Discard", "Invalidate", }; GR_STATIC_ASSERT(0 == kNone_InvalidateFBType); GR_STATIC_ASSERT(1 == kDiscard_InvalidateFBType); GR_STATIC_ASSERT(2 == kInvalidate_InvalidateFBType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kInvalidateFBTypeStr) == kLast_InvalidateFBType + 1); static const char* kMapBufferTypeStr[] = { "None", "MapBuffer", "MapBufferRange", "Chromium", }; GR_STATIC_ASSERT(0 == kNone_MapBufferType); GR_STATIC_ASSERT(1 == kMapBuffer_MapBufferType); GR_STATIC_ASSERT(2 == kMapBufferRange_MapBufferType); GR_STATIC_ASSERT(3 == kChromium_MapBufferType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kMapBufferTypeStr) == kLast_MapBufferType + 1); r.appendf("Core Profile: %s\n", (fIsCoreProfile ? "YES" : "NO")); r.appendf("MSAA Type: %s\n", kMSFBOExtStr[fMSFBOType]); r.appendf("FB Fetch Type: %s\n", kFBFetchTypeStr[fFBFetchType]); r.appendf("Invalidate FB Type: %s\n", kInvalidateFBTypeStr[fInvalidateFBType]); r.appendf("Map Buffer Type: %s\n", kMapBufferTypeStr[fMapBufferType]); r.appendf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors); r.appendf("Max FS Texture Units: %d\n", fMaxFragmentTextureUnits); if (!fIsCoreProfile) { r.appendf("Max Fixed Function Texture Coords: %d\n", fMaxFixedFunctionTextureCoords); } r.appendf("Max Vertex Attributes: %d\n", fMaxVertexAttributes); r.appendf("Support RGBA8 Render Buffer: %s\n", (fRGBA8RenderbufferSupport ? "YES": "NO")); r.appendf("BGRA is an internal format: %s\n", (fBGRAIsInternalFormat ? "YES": "NO")); r.appendf("Support texture swizzle: %s\n", (fTextureSwizzleSupport ? "YES": "NO")); r.appendf("Unpack Row length support: %s\n", (fUnpackRowLengthSupport ? "YES": "NO")); r.appendf("Unpack Flip Y support: %s\n", (fUnpackFlipYSupport ? "YES": "NO")); r.appendf("Pack Row length support: %s\n", (fPackRowLengthSupport ? "YES": "NO")); r.appendf("Pack Flip Y support: %s\n", (fPackFlipYSupport ? "YES": "NO")); r.appendf("Texture Usage support: %s\n", (fTextureUsageSupport ? "YES": "NO")); r.appendf("Texture Storage support: %s\n", (fTexStorageSupport ? "YES": "NO")); r.appendf("GL_R support: %s\n", (fTextureRedSupport ? "YES": "NO")); r.appendf("GL_ARB_imaging support: %s\n", (fImagingSupport ? "YES": "NO")); r.appendf("Two Format Limit: %s\n", (fTwoFormatLimit ? "YES": "NO")); r.appendf("Fragment coord conventions support: %s\n", (fFragCoordsConventionSupport ? "YES": "NO")); r.appendf("Vertex array object support: %s\n", (fVertexArrayObjectSupport ? "YES": "NO")); r.appendf("Use non-VBO for dynamic data: %s\n", (fUseNonVBOVertexAndIndexDynamicData ? "YES" : "NO")); r.appendf("Full screen clear is free: %s\n", (fFullClearIsFree ? "YES" : "NO")); r.appendf("Drops tile on zero divide: %s\n", (fDropsTileOnZeroDivide ? "YES" : "NO")); return r; }
static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider, bool miterStroke) { if (miterStroke) { static const uint16_t gMiterIndices[] = { 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, }; GR_STATIC_ASSERT(SK_ARRAY_COUNT(gMiterIndices) == kMiterIndexCnt); GR_DEFINE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey); return resourceProvider->refOrCreateInstancedIndexBuffer(gMiterIndices, kMiterIndexCnt, kNumMiterRectsInIndexBuffer, kMiterVertexCnt, gMiterIndexBufferKey); } else { /** * As in miter-stroke, index = a + b, and a is the current index, b is the shift * from the first index. The index layout: * outer AA line: 0~3, 4~7 * outer edge: 8~11, 12~15 * inner edge: 16~19 * inner AA line: 20~23 * Following comes a bevel-stroke rect and its indices: * * 4 7 * ********************************* * * ______________________________ * * * / 12 15 \ * * * / \ * * 0 * |8 16_____________________19 11 | * 3 * * | | | | * * * | | **************** | | * * * | | * 20 23 * | | * * * | | * * | | * * * | | * 21 22 * | | * * * | | **************** | | * * * | |____________________| | * * 1 * |9 17 18 10| * 2 * * \ / * * * \13 __________________________14/ * * * * * ********************************** * 5 6 */ static const uint16_t gBevelIndices[] = { // Draw outer AA, from outer AA line to outer edge, shift is 0. 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0, 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0, 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0, 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0, 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0, 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0, 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0, 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0, // Draw the stroke, from outer edge to inner edge, shift is 8. 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8, 1 + 8, 5 + 8, 9 + 8, 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8, 6 + 8, 2 + 8, 10 + 8, 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8, 3 + 8, 7 + 8, 11 + 8, 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8, 4 + 8, 0 + 8, 8 + 8, // Draw the inner AA, from inner edge to inner AA line, shift is 16. 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16, 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16, 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16, 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16, }; GR_STATIC_ASSERT(SK_ARRAY_COUNT(gBevelIndices) == kBevelIndexCnt); GR_DEFINE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey); return resourceProvider->refOrCreateInstancedIndexBuffer(gBevelIndices, kBevelIndexCnt, kNumBevelRectsInIndexBuffer, kBevelVertexCnt, gBevelIndexBufferKey); } }
virtual void onDraw(SkCanvas* canvas) { struct FillAndName { SkPath::FillType fFill; const char* fName; }; static const FillAndName gFills[] = { {SkPath::kWinding_FillType, "Winding"}, {SkPath::kEvenOdd_FillType, "Even / Odd"}, {SkPath::kInverseWinding_FillType, "Inverse Winding"}, {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, }; struct StyleAndName { SkPaint::Style fStyle; const char* fName; }; static const StyleAndName gStyles[] = { {SkPaint::kFill_Style, "Fill"}, {SkPaint::kStroke_Style, "Stroke"}, {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, }; struct CapAndName { SkPaint::Cap fCap; SkPaint::Join fJoin; const char* fName; }; static const CapAndName gCaps[] = { {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} }; struct PathAndName { SkPath fPath; const char* fName; }; PathAndName path; path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1); path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1); path.fPath.close(); path.fName = "moveTo-line-close"; SkPaint titlePaint; titlePaint.setColor(SK_ColorBLACK); titlePaint.setAntiAlias(true); titlePaint.setLCDRenderText(true); titlePaint.setTextSize(15 * SK_Scalar1); const char title[] = "Line Closed Drawn Into Rectangle Clips With " "Indicated Style, Fill and Linecaps, with stroke width 10"; canvas->drawText(title, strlen(title), 20 * SK_Scalar1, 20 * SK_Scalar1, titlePaint); SkLCGRandom rand; SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); canvas->save(); canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); canvas->save(); for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { if (0 < cap) { canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); } canvas->save(); for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { if (0 < fill) { canvas->translate(0, rect.height() + 40 * SK_Scalar1); } canvas->save(); for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { if (0 < style) { canvas->translate(rect.width() + 40 * SK_Scalar1, 0); } SkColor color = 0xff007000; this->drawPath(path.fPath, canvas, color, rect, gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, gFills[fill].fFill, SK_Scalar1*10); SkPaint rectPaint; rectPaint.setColor(SK_ColorBLACK); rectPaint.setStyle(SkPaint::kStroke_Style); rectPaint.setStrokeWidth(-1); rectPaint.setAntiAlias(true); canvas->drawRect(rect, rectPaint); SkPaint labelPaint; labelPaint.setColor(color); labelPaint.setAntiAlias(true); labelPaint.setLCDRenderText(true); labelPaint.setTextSize(10 * SK_Scalar1); canvas->drawText(gStyles[style].fName, strlen(gStyles[style].fName), 0, rect.height() + 12 * SK_Scalar1, labelPaint); canvas->drawText(gFills[fill].fName, strlen(gFills[fill].fName), 0, rect.height() + 24 * SK_Scalar1, labelPaint); canvas->drawText(gCaps[cap].fName, strlen(gCaps[cap].fName), 0, rect.height() + 36 * SK_Scalar1, labelPaint); } canvas->restore(); } canvas->restore(); } canvas->restore(); canvas->restore(); }
bool Window_unix::initWindow(Display* display) { if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) { this->closeWindow(); } // we already have a window if (fDisplay) { return true; } fDisplay = display; constexpr int initialWidth = 1280; constexpr int initialHeight = 960; // Attempt to create a window that supports GL // We prefer the more recent glXChooseFBConfig but fall back to glXChooseVisual. They have // slight differences in how attributes are specified. static int constexpr kChooseFBConfigAtt[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DOUBLEBUFFER, True, GLX_STENCIL_SIZE, 8, None }; // For some reason glXChooseVisual takes a non-const pointer to the attributes. int chooseVisualAtt[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 8, None }; SkASSERT(nullptr == fVisualInfo); if (fRequestedDisplayParams.fMSAASampleCount > 1) { static const GLint kChooseFBConifgAttCnt = SK_ARRAY_COUNT(kChooseFBConfigAtt); GLint msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 4]; memcpy(msaaChooseFBConfigAtt, kChooseFBConfigAtt, sizeof(kChooseFBConfigAtt)); SkASSERT(None == msaaChooseFBConfigAtt[kChooseFBConifgAttCnt - 1]); msaaChooseFBConfigAtt[kChooseFBConifgAttCnt - 1] = GLX_SAMPLE_BUFFERS_ARB; msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 0] = 1; msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 1] = GLX_SAMPLES_ARB; msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 2] = fRequestedDisplayParams.fMSAASampleCount; msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 3] = None; int n; fFBConfig = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), msaaChooseFBConfigAtt, &n); if (n > 0) { fVisualInfo = glXGetVisualFromFBConfig(fDisplay, *fFBConfig); } else { static const GLint kChooseVisualAttCnt = SK_ARRAY_COUNT(chooseVisualAtt); GLint msaaChooseVisualAtt[kChooseVisualAttCnt + 4]; memcpy(msaaChooseVisualAtt, chooseVisualAtt, sizeof(chooseVisualAtt)); SkASSERT(None == msaaChooseVisualAtt[kChooseVisualAttCnt - 1]); msaaChooseFBConfigAtt[kChooseVisualAttCnt - 1] = GLX_SAMPLE_BUFFERS_ARB; msaaChooseFBConfigAtt[kChooseVisualAttCnt + 0] = 1; msaaChooseFBConfigAtt[kChooseVisualAttCnt + 1] = GLX_SAMPLES_ARB; msaaChooseFBConfigAtt[kChooseVisualAttCnt + 2] = fRequestedDisplayParams.fMSAASampleCount; msaaChooseFBConfigAtt[kChooseVisualAttCnt + 3] = None; fVisualInfo = glXChooseVisual(display, DefaultScreen(display), msaaChooseVisualAtt); fFBConfig = nullptr; } } if (nullptr == fVisualInfo) { int n; fFBConfig = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), kChooseFBConfigAtt, &n); if (n > 0) { fVisualInfo = glXGetVisualFromFBConfig(fDisplay, *fFBConfig); } else { fVisualInfo = glXChooseVisual(display, DefaultScreen(display), chooseVisualAtt); fFBConfig = nullptr; } } if (fVisualInfo) { Colormap colorMap = XCreateColormap(display, RootWindow(display, fVisualInfo->screen), fVisualInfo->visual, AllocNone); XSetWindowAttributes swa; swa.colormap = colorMap; swa.event_mask = kEventMask; fWindow = XCreateWindow(display, RootWindow(display, fVisualInfo->screen), 0, 0, // x, y initialWidth, initialHeight, 0, // border width fVisualInfo->depth, InputOutput, fVisualInfo->visual, CWEventMask | CWColormap, &swa); } else { // Create a simple window instead. We will not be able to show GL fWindow = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, // x, y initialWidth, initialHeight, 0, // border width 0, // border value 0); // background value XSelectInput(display, fWindow, kEventMask); } if (!fWindow) { return false; } fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount; // set up to catch window delete message fWmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False); XSetWMProtocols(display, fWindow, &fWmDeleteMessage, 1); // add to hashtable of windows gWindowMap.add(this); // init event variables fPendingPaint = false; fPendingResize = false; return true; }