int tool_main(int argc, char** argv) { SetupCrashHandler(); SkAutoGraphics ag; SkCommandLineFlags::Parse(argc, argv); const double overhead = estimate_timer_overhead(); if (FLAGS_verbose) { // No header. } else if (FLAGS_quiet) { SkDebugf("min\tbench\tconfig\n"); } else { SkDebugf("loops\tmin\tmean\tmax\tstddev\tbench\tconfig\n"); } for (const BenchRegistry* r = BenchRegistry::Head(); r != NULL; r = r->next()) { SkAutoTDelete<Benchmark> bench(r->factory()(NULL)); if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { continue; } SkTDArray<SkSurface*> surfaces; SkTDArray<const char*> configs; create_surfaces(bench.get(), &surfaces, &configs); bench->preDraw(); for (int j = 0; j < surfaces.count(); j++) { SkCanvas* canvas = surfaces[j] ? surfaces[j]->getCanvas() : NULL; const char* config = configs[j]; bench->draw(1, canvas); // Just paranoid warmup. safe_flush(canvas); const int loops = guess_loops(overhead, bench.get(), canvas); SkAutoTMalloc<double> samples(FLAGS_samples); WallTimer timer; for (int i = 0; i < FLAGS_samples; i++) { timer.start(); bench->draw(loops, canvas); safe_flush(canvas); timer.end(); samples[i] = timer.fWall / loops; } Stats stats(samples.get(), FLAGS_samples); if (FLAGS_verbose) { for (int i = 0; i < FLAGS_samples; i++) { SkDebugf("%s ", humanize(samples[i]).c_str()); } SkDebugf("%s\n", bench->getName()); } else if (FLAGS_quiet) { if (configs.count() == 1) { config = ""; // Only print the config if we run the same bench on more than one. } SkDebugf("%s\t%s\t%s\n", humanize(stats.min).c_str(), bench->getName(), config); } else { const double stddev_percent = 100 * sqrt(stats.var) / stats.mean; SkDebugf("%d\t%s\t%s\t%s\t%.0f%%\t%s\t%s\n" , loops , humanize(stats.min).c_str() , humanize(stats.mean).c_str() , humanize(stats.max).c_str() , stddev_percent , bench->getName() , config ); } } surfaces.deleteAll(); } return 0; }
void TestRunner::render() { SkTaskGroup tg; for (int index = 0; index < fRunnables.count(); ++ index) { tg.add(fRunnables[index]); } }
void onDraw(SkCanvas* canvas) override { fShader = gBleedRec[fBT].fShaderMaker(); canvas->clear(SK_ColorGRAY); SkTDArray<SkMatrix> matrices; // Draw with identity *matrices.append() = SkMatrix::I(); // Draw with rotation and scale down in x, up in y. SkMatrix m; constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing); m.setTranslate(0, kBottom); m.preRotate(15.f, 0, kBottom + kBlockSpacing); m.preScale(0.71f, 1.22f); *matrices.append() = m; // Align the next set with the middle of the previous in y, translated to the right in x. SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} }; matrices[matrices.count()-1].mapPoints(corners, 4); SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4; SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX), SkTMax(corners[2].fX, corners[3].fX)); m.setTranslate(x, y); m.preScale(0.2f, 0.2f); *matrices.append() = m; SkScalar maxX = 0; for (int antiAlias = 0; antiAlias < 2; ++antiAlias) { canvas->save(); canvas->translate(maxX, 0); for (int m = 0; m < matrices.count(); ++m) { canvas->save(); canvas->concat(matrices[m]); bool aa = SkToBool(antiAlias); // First draw a column with no bleeding and no filtering this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); // Then draw a column with no bleeding and low filtering this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); // Then draw a column with no bleeding and high filtering this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur) this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); // Then draw a column with bleeding and low filtering this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); // Finally draw a column with bleeding and high filtering this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } }; matrices[m].mapPoints(corners, 4); SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX), SkTMax(corners[2].fX, corners[3].fX)); maxX = SkTMax(maxX, x); canvas->restore(); } canvas->restore(); } }
void onDraw(SkCanvas* canvas) override { 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; localMatrices.append()->fMatrix.reset(); localMatrices.top().fLabel = "Identity"; localMatrices.append()->fMatrix.setScale(2.5f, 0.2f); localMatrices.top().fLabel = "Scale"; localMatrices.append()->fMatrix.setRotate(45.f); localMatrices.top().fLabel = "Rotate"; localMatrices.append()->fMatrix.reset(); localMatrices.top().fMatrix.setPerspX(-0.007f); localMatrices.top().fMatrix.setPerspY(+0.008f); localMatrices.top().fLabel = "Persp"; static SkBitmap bmp; if (bmp.isNull()) { makebm(&bmp, kPointSize / 2, kPointSize / 2); } SkPaint fillPaint; fillPaint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&fillPaint); fillPaint.setTextSize(SkIntToScalar(kPointSize)); fillPaint.setFilterQuality(kLow_SkFilterQuality); SkPaint outlinePaint; outlinePaint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&outlinePaint); outlinePaint.setTextSize(SkIntToScalar(kPointSize)); outlinePaint.setStyle(SkPaint::kStroke_Style); outlinePaint.setStrokeWidth(0.f); SkScalar w = fillPaint.measureText(kText, kTextLen); static SkScalar kPadY = 0.5f * kPointSize; static SkScalar kPadX = 1.5f * kPointSize; SkPaint strokePaint(fillPaint); strokePaint.setStyle(SkPaint::kStroke_Style); strokePaint.setStrokeWidth(kPointSize * 0.1f); SkPaint labelPaint; labelPaint.setColor(0xff000000); labelPaint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&labelPaint); labelPaint.setTextSize(12.f); canvas->translate(15.f, 15.f); canvas->drawBitmap(bmp, 0, 0); canvas->translate(0, bmp.height() + labelPaint.getTextSize() + 15.f); static const char kLabelLabel[] = "localM / canvasM"; canvas->drawText(kLabelLabel, strlen(kLabelLabel), 0, 0, labelPaint); canvas->translate(0, 15.f); canvas->save(); SkScalar maxLabelW = 0; canvas->translate(0, kPadY / 2 + kPointSize); for (int lm = 0; lm < localMatrices.count(); ++lm) { canvas->drawText(matrices[lm].fLabel, strlen(matrices[lm].fLabel), 0, labelPaint.getTextSize() - 1, labelPaint); SkScalar labelW = labelPaint.measureText(matrices[lm].fLabel, strlen(matrices[lm].fLabel)); maxLabelW = SkMaxScalar(maxLabelW, labelW); canvas->translate(0.f, 2 * kPointSize + 2.5f * kPadY); } canvas->restore(); canvas->translate(maxLabelW + kPadX / 2.f, 0.f); for (int s = 0; s < 2; ++s) { SkPaint& paint = s ? strokePaint : fillPaint; SkScalar columnH = 0; for (int m = 0; m < matrices.count(); ++m) { columnH = 0; canvas->save(); canvas->drawText(matrices[m].fLabel, strlen(matrices[m].fLabel), 0, labelPaint.getTextSize() - 1, labelPaint); canvas->translate(0, kPadY / 2 + kPointSize); columnH += kPadY / 2 + kPointSize; for (int lm = 0; lm < localMatrices.count(); ++lm) { paint.setShader( SkShader::CreateBitmapShader(bmp, SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode, &localMatrices[lm].fMatrix))->unref(); canvas->save(); canvas->concat(matrices[m].fMatrix); canvas->drawText(kText, kTextLen, 0, 0, paint); canvas->drawText(kText, kTextLen, 0, 0, outlinePaint); canvas->restore(); SkPath path; path.arcTo(SkRect::MakeXYWH(-0.1f * w, 0.f, 1.2f * w, 2.f * kPointSize), 225.f, 359.f, false); path.close(); canvas->translate(0.f, kPointSize + kPadY); columnH += kPointSize + kPadY; canvas->save(); canvas->concat(matrices[m].fMatrix); canvas->drawTextOnPath(kText, kTextLen, path, NULL, paint); canvas->drawTextOnPath(kText, kTextLen, path, NULL, outlinePaint); canvas->restore(); SkPaint stroke; stroke.setStyle(SkPaint::kStroke_Style); canvas->translate(0.f, kPointSize + kPadY); columnH += kPointSize + kPadY; } canvas->restore(); canvas->translate(w + kPadX, 0.f); } if (0 == s) { canvas->drawLine(0.f, -kPadY, 0.f, columnH + kPadY, outlinePaint); canvas->translate(kPadX / 2, 0.f); static const char kFillLabel[] = "Filled"; static const char kStrokeLabel[] = "Stroked"; SkScalar y = columnH + kPadY / 2; SkScalar fillX = -outlinePaint.measureText(kFillLabel, strlen(kFillLabel)) - kPadX; SkScalar strokeX = kPadX; canvas->drawText(kFillLabel, strlen(kFillLabel), fillX, y, labelPaint); canvas->drawText(kStrokeLabel, strlen(kStrokeLabel), strokeX, y, labelPaint); } } }
void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { for (int i = 0; i < shaderIDs.count(); ++i) { GL_CALL(DeleteShader(shaderIDs[i])); } }
// If we're isolating all GPU-bound work to one thread (the default), this function runs all that. static void run_enclave_and_gpu_tests(SkTArray<Task>* tasks) { run_enclave(tasks); for (int i = 0; i < gGPUTests.count(); i++) { run_test(&gGPUTests[i]); } }
static void test_gatherpixelrefs(skiatest::Reporter* reporter) { const int IW = 8; const int IH = IW; const SkScalar W = SkIntToScalar(IW); const SkScalar H = W; static const int N = 4; SkBitmap bm[N]; SkPixelRef* refs[N]; const SkPoint pos[] = { { 0, 0 }, { W, 0 }, { 0, H }, { W, H } }; // Our convention is that the color components contain the index of their // corresponding bitmap/pixelref for (int i = 0; i < N; ++i) { make_bm(&bm[i], IW, IH, SkColorSetARGB(0xFF, i, i, i), true); refs[i] = bm[i].pixelRef(); } static const DrawBitmapProc procs[] = { drawbitmap_proc, drawbitmaprect_proc, drawshader_proc }; SkRandom rand; for (size_t k = 0; k < SK_ARRAY_COUNT(procs); ++k) { SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, N, procs[k])); // quick check for a small piece of each quadrant, which should just // contain 1 bitmap. for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) { SkRect r; r.set(2, 2, W - 2, H - 2); r.offset(pos[i].fX, pos[i].fY); SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r)); REPORTER_ASSERT(reporter, data); int count = data->size() / sizeof(SkPixelRef*); REPORTER_ASSERT(reporter, 1 == count); REPORTER_ASSERT(reporter, *(SkPixelRef**)data->data() == refs[i]); } // Test a bunch of random (mostly) rects, and compare the gather results // with a deduced list of refs by looking at the colors drawn. for (int j = 0; j < 100; ++j) { SkRect r; rand_rect(&r, rand, 2*W, 2*H); SkBitmap result; draw(pic, r, &result); SkTDArray<SkPixelRef*> array; SkData* data = SkPictureUtils::GatherPixelRefs(pic, r); size_t dataSize = data ? data->size() : 0; int gatherCount = dataSize / sizeof(SkPixelRef*); SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize); SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL; SkAutoDataUnref adu(data); gather_from_colors(result, refs, N, &array); /* * GatherPixelRefs is conservative, so it can return more bitmaps * that we actually can see (usually because of conservative bounds * inflation for antialiasing). Thus our check here is only that * Gather didn't miss any that we actually saw. Even that isn't * a strict requirement on Gather, which is meant to be quick and * only mostly-correct, but at the moment this test should work. */ for (int i = 0; i < array.count(); ++i) { bool found = find(gatherRefs, array[i], gatherCount); REPORTER_ASSERT(reporter, found); #if 0 // enable this block of code to debug failures, as it will rerun // the case that failed. if (!found) { SkData* data = SkPictureUtils::GatherPixelRefs(pic, r); size_t dataSize = data ? data->size() : 0; } #endif } } } }
/* check start and end of each contour if not the same, record them match them up connect closest reassemble contour pieces into new path */ void Assemble(const SkPathWriter& path, SkPathWriter* simple) { SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContourHead contour; SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(nullptr)); #if DEBUG_SHOW_TEST_NAME SkDebugf("</div>\n"); #endif #if DEBUG_PATH_CONSTRUCTION SkDebugf("%s\n", __FUNCTION__); #endif SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); builder.finish(&allocator); SkTDArray<const SkOpContour* > runs; // indices of partial contours const SkOpContour* eContour = builder.head(); do { if (!eContour->count()) { continue; } const SkPoint& eStart = eContour->start(); const SkPoint& eEnd = eContour->end(); #if DEBUG_ASSEMBLE SkDebugf("%s contour", __FUNCTION__); if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { SkDebugf("[%d]", runs.count()); } else { SkDebugf(" "); } SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); #endif if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { eContour->toPath(simple); continue; } *runs.append() = eContour; } while ((eContour = eContour->next())); int count = runs.count(); if (count == 0) { return; } SkTDArray<int> sLink, eLink; sLink.append(count); eLink.append(count); int rIndex, iIndex; for (rIndex = 0; rIndex < count; ++rIndex) { sLink[rIndex] = eLink[rIndex] = SK_MaxS32; } const int ends = count * 2; // all starts and ends const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 SkTDArray<double> distances; distances.append(entries); for (rIndex = 0; rIndex < ends - 1; ++rIndex) { const SkOpContour* oContour = runs[rIndex >> 1]; const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start(); const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) * ends - rIndex - 1; for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { const SkOpContour* iContour = runs[iIndex >> 1]; const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start(); double dx = iPt.fX - oPt.fX; double dy = iPt.fY - oPt.fY; double dist = dx * dx + dy * dy; distances[row + iIndex] = dist; // oStart distance from iStart } } SkTDArray<int> sortedDist; sortedDist.append(entries); for (rIndex = 0; rIndex < entries; ++rIndex) { sortedDist[rIndex] = rIndex; } SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); int remaining = count; // number of start/end pairs for (rIndex = 0; rIndex < entries; ++rIndex) { int pair = sortedDist[rIndex]; int row = pair / ends; int col = pair - row * ends; int thingOne = row < col ? row : ends - row - 2; int ndxOne = thingOne >> 1; bool endOne = thingOne & 1; int* linkOne = endOne ? eLink.begin() : sLink.begin(); if (linkOne[ndxOne] != SK_MaxS32) { continue; } int thingTwo = row < col ? col : ends - row + col - 1; int ndxTwo = thingTwo >> 1; bool endTwo = thingTwo & 1; int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); if (linkTwo[ndxTwo] != SK_MaxS32) { continue; } SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); bool flip = endOne == endTwo; linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; if (!--remaining) { break; } } SkASSERT(!remaining); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { int s = sLink[rIndex]; int e = eLink[rIndex]; SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); } #endif rIndex = 0; do { bool forward = true; bool first = true; int sIndex = sLink[rIndex]; SkASSERT(sIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; int eIndex; if (sIndex < 0) { eIndex = sLink[~sIndex]; sLink[~sIndex] = SK_MaxS32; } else { eIndex = eLink[sIndex]; eLink[sIndex] = SK_MaxS32; } SkASSERT(eIndex != SK_MaxS32); #if DEBUG_ASSEMBLE SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', eIndex < 0 ? ~eIndex : eIndex); #endif do { const SkOpContour* contour = runs[rIndex]; if (first) { first = false; const SkPoint* startPtr = &contour->start(); simple->deferredMove(startPtr[0]); } if (forward) { contour->toPartialForward(simple); } else { contour->toPartialBackward(simple); } #if DEBUG_ASSEMBLE SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); #endif if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { simple->close(); break; } if (forward) { eIndex = eLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); eLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(sLink[eIndex] == rIndex); sLink[eIndex] = SK_MaxS32; } else { SkASSERT(eLink[~eIndex] == ~rIndex); eLink[~eIndex] = SK_MaxS32; } } else { eIndex = sLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(eLink[eIndex] == rIndex); eLink[eIndex] = SK_MaxS32; } else { SkASSERT(sLink[~eIndex] == ~rIndex); sLink[~eIndex] = SK_MaxS32; } } rIndex = eIndex; if (rIndex < 0) { forward ^= 1; rIndex = ~rIndex; } } while (true); for (rIndex = 0; rIndex < count; ++rIndex) { if (sLink[rIndex] != SK_MaxS32) { break; } } } while (rIndex < count); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { SkASSERT(sLink[rIndex] == SK_MaxS32); SkASSERT(eLink[rIndex] == SK_MaxS32); } #endif }
bool SkPaint2GrPaintNoShader(GrContext* context, GrRenderTarget* rt, const SkPaint& skPaint, GrColor paintColor, bool constantColor, GrPaint* grPaint) { grPaint->setDither(skPaint.isDither()); grPaint->setAntiAlias(skPaint.isAntiAlias()); SkXfermode* mode = skPaint.getXfermode(); GrXPFactory* xpFactory = nullptr; if (!SkXfermode::AsXPFactory(mode, &xpFactory)) { // Fall back to src-over // return false here? xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode); } SkASSERT(xpFactory); grPaint->setXPFactory(xpFactory)->unref(); //set the color of the paint to the one of the parameter grPaint->setColor(paintColor); SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { // if the source color is a constant then apply the filter here once rather than per pixel // in a shader. if (constantColor) { SkColor filtered = colorFilter->filterColor(skPaint.getColor()); grPaint->setColor(SkColor2GrColor(filtered)); } else { SkTDArray<GrFragmentProcessor*> array; // return false if failed? if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(), &array)) { for (int i = 0; i < array.count(); ++i) { grPaint->addColorFragmentProcessor(array[i]); array[i]->unref(); } } } } #ifndef SK_IGNORE_GPU_DITHER // If the dither flag is set, then we need to see if the underlying context // supports it. If not, then install a dither effect. if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) { // What are we rendering into? SkASSERT(rt); // Suspect the dithering flag has no effect on these configs, otherwise // fall back on setting the appropriate state. if (GrPixelConfigIs8888(rt->config()) || GrPixelConfigIs8888(rt->config())) { // The dither flag is set and the target is likely // not going to be dithered by the GPU. SkAutoTUnref<GrFragmentProcessor> fp(GrDitherEffect::Create()); if (fp.get()) { grPaint->addColorFragmentProcessor(fp); grPaint->setDither(false); } } } #endif return true; }
SkPath makePath() { SkPath path; for (uint32_t cIndex = 0; cIndex < fPathContourCount; ++cIndex) { uint32_t segments = makeSegmentCount(); for (uint32_t sIndex = 0; sIndex < segments; ++sIndex) { RandomAddPath addPathType = makeAddPathType(); ++fAddCount; if (fPrintName) { SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomAddPathNames[addPathType]); } switch (addPathType) { case kAddArc: { SkRect oval = makeRect(); SkScalar startAngle = makeAngle(); SkScalar sweepAngle = makeAngle(); path.addArc(oval, startAngle, sweepAngle); validate(path); } break; case kAddRoundRect1: { SkRect rect = makeRect(); SkScalar rx = makeScalar(), ry = makeScalar(); SkPath::Direction dir = makeDirection(); path.addRoundRect(rect, rx, ry, dir); validate(path); } break; case kAddRoundRect2: { SkRect rect = makeRect(); SkScalar radii[8]; makeScalarArray(SK_ARRAY_COUNT(radii), radii); SkPath::Direction dir = makeDirection(); path.addRoundRect(rect, radii, dir); validate(path); } break; case kAddRRect: { SkRRect rrect = makeRRect(); SkPath::Direction dir = makeDirection(); path.addRRect(rrect, dir); validate(path); } break; case kAddPoly: { SkTDArray<SkPoint> points; makePointArray(&points); bool close = makeBool(); path.addPoly(&points[0], points.count(), close); validate(path); } break; case kAddPath1: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); SkScalar dx = makeScalar(); SkScalar dy = makeScalar(); SkPath::AddPathMode mode = makeAddPathMode(); path.addPath(src, dx, dy, mode); --fPathDepth; validate(path); } break; case kAddPath2: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); SkPath::AddPathMode mode = makeAddPathMode(); path.addPath(src, mode); --fPathDepth; validate(path); } break; case kAddPath3: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); SkMatrix matrix = makeMatrix(); SkPath::AddPathMode mode = makeAddPathMode(); path.addPath(src, matrix, mode); --fPathDepth; validate(path); } break; case kReverseAddPath: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); path.reverseAddPath(src); --fPathDepth; validate(path); } break; case kMoveToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.moveTo(x, y); validate(path); } break; case kRMoveToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.rMoveTo(x, y); validate(path); } break; case kLineToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.lineTo(x, y); validate(path); } break; case kRLineToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.rLineTo(x, y); validate(path); } break; case kQuadToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.quadTo(pt[0], pt[1]); validate(path); } break; case kRQuadToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY); validate(path); } break; case kConicToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); SkScalar weight = makeScalar(); path.conicTo(pt[0], pt[1], weight); validate(path); } break; case kRConicToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); SkScalar weight = makeScalar(); path.rConicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, weight); validate(path); } break; case kCubicToPath: { SkPoint pt[3]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.cubicTo(pt[0], pt[1], pt[2]); validate(path); } break; case kRCubicToPath: { SkPoint pt[3]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.rCubicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, pt[2].fX, pt[2].fY); validate(path); } break; case kArcToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); SkScalar radius = makeScalar(); path.arcTo(pt[0], pt[1], radius); validate(path); } break; case kArcTo2Path: { SkRect oval = makeRect(); SkScalar startAngle = makeAngle(); SkScalar sweepAngle = makeAngle(); bool forceMoveTo = makeBool(); path.arcTo(oval, startAngle, sweepAngle, forceMoveTo); validate(path); } break; case kClosePath: path.close(); validate(path); break; } } } return path; }
int dm_main() { setbuf(stdout, nullptr); setup_crash_handler(); if (FLAGS_verbose) { gVLog = stderr; } else if (!FLAGS_writePath.isEmpty()) { sk_mkdir(FLAGS_writePath[0]); gVLog = freopen(SkOSPath::Join(FLAGS_writePath[0], "verbose.log").c_str(), "w", stderr); } if (FLAGS_forceSRGB) { gDefaultProfileIsSRGB = true; } JsonWriter::DumpJson(); // It's handy for the bots to assume this is ~never missing. SkAutoGraphics ag; SkTaskGroup::Enabler enabled(FLAGS_threads); gCreateTypefaceDelegate = &create_from_name; { SkString testResourcePath = GetResourcePath("color_wheel.png"); SkFILEStream testResource(testResourcePath.c_str()); if (!testResource.isValid()) { info("Some resources are missing. Do you need to set --resourcePath?\n"); } } gather_gold(); gather_uninteresting_hashes(); if (!gather_srcs()) { return 1; } if (!gather_sinks()) { return 1; } gather_tests(); gPending = gSrcs.count() * gSinks.count() + gParallelTests.count() + gSerialTests.count(); info("%d srcs * %d sinks + %d tests == %d tasks", gSrcs.count(), gSinks.count(), gParallelTests.count() + gSerialTests.count(), gPending); SkAutoTDelete<SkThread> statusThread(start_status_thread()); // Kick off as much parallel work as we can, making note of any serial work we'll need to do. SkTaskGroup parallel; SkTArray<Task> serial; for (auto& sink : gSinks) for (auto& src : gSrcs) { if (src->veto(sink->flags()) || is_blacklisted(sink.tag.c_str(), src.tag.c_str(), src.options.c_str(), src->name().c_str())) { SkAutoTAcquire<SkSpinlock> lock(gMutex); gPending--; continue; } Task task(src, sink); if (src->serial() || sink->serial()) { serial.push_back(task); } else { parallel.add([task] { Task::Run(task); }); } } for (auto test : gParallelTests) { parallel.add([test] { run_test(test); }); } // With the parallel work running, run serial tasks and tests here on main thread. for (auto task : serial) { Task::Run(task); } for (auto test : gSerialTests) { run_test(test); } // Wait for any remaining parallel work to complete (including any spun off of serial tasks). parallel.wait(); gDefinitelyThreadSafeWork.wait(); // We'd better have run everything. SkASSERT(gPending == 0); // Make sure we've flushed all our results to disk. JsonWriter::DumpJson(); // At this point we're back in single-threaded land. sk_tool_utils::release_portable_typefaces(); if (gFailures.count() > 0) { info("Failures:\n"); for (int i = 0; i < gFailures.count(); i++) { info("\t%s\n", gFailures[i].c_str()); } info("%d failures\n", gFailures.count()); return 1; } #ifdef SK_PDF_IMAGE_STATS SkPDFImageDumpStats(); #endif // SK_PDF_IMAGE_STATS print_status(); info("Finished!\n"); return 0; }
static void output_font(SkTypeface* face, const char* name, SkTypeface::Style style, const char* used, FILE* out) { int emSize = face->getUnitsPerEm() * 2; SkPaint paint; paint.setAntiAlias(true); paint.setTextAlign(SkPaint::kLeft_Align); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); paint.setTextSize(emSize); SkSafeUnref(paint.setTypeface(face)); SkTDArray<SkPath::Verb> verbs; SkTDArray<unsigned> charCodes; SkTDArray<SkScalar> widths; SkString ptsOut; output_path_data(paint, used, emSize, &ptsOut, &verbs, &charCodes, &widths); SkString fontnameStr(name); SkString strippedStr = strip_spaces(fontnameStr); strippedStr.appendf("%s", gStyleName[style]); const char* fontname = strippedStr.c_str(); fprintf(out, "const SkScalar %sPoints[] = {\n", fontname); ptsOut = strip_final(ptsOut); fprintf(out, "%s", ptsOut.c_str()); fprintf(out, "\n};\n\n"); fprintf(out, "const unsigned char %sVerbs[] = {\n", fontname); int verbCount = verbs.count(); int outChCount = 0; for (int index = 0; index < verbCount;) { SkPath::Verb verb = verbs[index]; SkASSERT(verb >= SkPath::kMove_Verb && verb <= SkPath::kDone_Verb); SkASSERT((unsigned) verb == (unsigned char) verb); fprintf(out, "%u", verb); if (++index < verbCount) { outChCount += 3; fprintf(out, "%c", ','); if (outChCount >= kMaxLineLength) { outChCount = 0; fprintf(out, "%c", '\n'); } else { fprintf(out, "%c", ' '); } } } fprintf(out, "\n};\n\n"); fprintf(out, "const unsigned %sCharCodes[] = {\n", fontname); int offsetCount = charCodes.count(); for (int index = 0; index < offsetCount;) { unsigned offset = charCodes[index]; fprintf(out, "%u", offset); if (++index < offsetCount) { outChCount += offset_str_len(offset) + 2; fprintf(out, "%c", ','); if (outChCount >= kMaxLineLength) { outChCount = 0; fprintf(out, "%c", '\n'); } else { fprintf(out, "%c", ' '); } } } fprintf(out, "\n};\n\n"); SkString widthsStr; fprintf(out, "const SkFixed %sWidths[] = {\n", fontname); for (int index = 0; index < offsetCount; ++index) { output_fixed(widths[index], emSize, &widthsStr); } widthsStr = strip_final(widthsStr); fprintf(out, "%s\n};\n\n", widthsStr.c_str()); fprintf(out, "const int %sCharCodesCount = (int) SK_ARRAY_COUNT(%sCharCodes);\n\n", fontname, fontname); SkPaint::FontMetrics metrics; paint.getFontMetrics(&metrics); fprintf(out, "const SkPaint::FontMetrics %sMetrics = {\n", fontname); SkString metricsStr; metricsStr.printf("0x%08x, ", metrics.fFlags); output_scalar(metrics.fTop, emSize, &metricsStr); output_scalar(metrics.fAscent, emSize, &metricsStr); output_scalar(metrics.fDescent, emSize, &metricsStr); output_scalar(metrics.fBottom, emSize, &metricsStr); output_scalar(metrics.fLeading, emSize, &metricsStr); output_scalar(metrics.fAvgCharWidth, emSize, &metricsStr); output_scalar(metrics.fMaxCharWidth, emSize, &metricsStr); output_scalar(metrics.fXMin, emSize, &metricsStr); output_scalar(metrics.fXMax, emSize, &metricsStr); output_scalar(metrics.fXHeight, emSize, &metricsStr); output_scalar(metrics.fCapHeight, emSize, &metricsStr); output_scalar(metrics.fUnderlineThickness, emSize, &metricsStr); output_scalar(metrics.fUnderlinePosition, emSize, &metricsStr); metricsStr = strip_final(metricsStr); fprintf(out, "%s\n};\n\n", metricsStr.c_str()); }
void SkCommandLineFlags::Parse(int argc, char** argv) { // Only allow calling this function once. static bool gOnce; if (gOnce) { SkDebugf("Parse should only be called once at the beginning of main!\n"); SkASSERT(false); return; } gOnce = true; bool helpPrinted = false; bool flagsPrinted = false; // Loop over argv, starting with 1, since the first is just the name of the program. for (int i = 1; i < argc; i++) { if (0 == strcmp("-h", argv[i]) || 0 == strcmp("--help", argv[i])) { // Print help message. SkTDArray<const char*> helpFlags; for (int j = i + 1; j < argc; j++) { if (SkStrStartsWith(argv[j], '-')) { break; } helpFlags.append(1, &argv[j]); } if (0 == helpFlags.count()) { // Only print general help message if help for specific flags is not requested. SkDebugf("%s\n%s\n", argv[0], gUsage.c_str()); } if (!flagsPrinted) { SkDebugf("Flags:\n"); flagsPrinted = true; } if (0 == helpFlags.count()) { // If no flags followed --help, print them all SkTDArray<SkFlagInfo*> allFlags; for (SkFlagInfo* flag = SkCommandLineFlags::gHead; flag; flag = flag->next()) { allFlags.push(flag); } SkTQSort(&allFlags[0], &allFlags[allFlags.count() - 1], CompareFlagsByName()); for (int i = 0; i < allFlags.count(); ++i) { print_help_for_flag(allFlags[i]); if (allFlags[i]->extendedHelp().size() > 0) { SkDebugf(" Use '--help %s' for more information.\n", allFlags[i]->name().c_str()); } } } else { for (SkFlagInfo* flag = SkCommandLineFlags::gHead; flag; flag = flag->next()) { for (int k = 0; k < helpFlags.count(); k++) { if (flag->name().equals(helpFlags[k]) || flag->shortName().equals(helpFlags[k])) { print_extended_help_for_flag(flag); helpFlags.remove(k); break; } } } } if (helpFlags.count() > 0) { SkDebugf("Requested help for unrecognized flags:\n"); for (int k = 0; k < helpFlags.count(); k++) { SkDebugf(" --%s\n", helpFlags[k]); } } helpPrinted = true; } if (!helpPrinted) { SkFlagInfo* matchedFlag = nullptr; SkFlagInfo* flag = gHead; int startI = i; while (flag != nullptr) { if (flag->match(argv[startI])) { i = startI; if (matchedFlag) { // Don't redefine the same flag with different types. SkASSERT(matchedFlag->getFlagType() == flag->getFlagType()); } else { matchedFlag = flag; } switch (flag->getFlagType()) { case SkFlagInfo::kBool_FlagType: // Can be handled by match, above, but can also be set by the next // string. if (i+1 < argc && !SkStrStartsWith(argv[i+1], '-')) { i++; bool value; if (parse_bool_arg(argv[i], &value)) { flag->setBool(value); } } break; case SkFlagInfo::kString_FlagType: flag->resetStrings(); // Add all arguments until another flag is reached. while (i+1 < argc) { char* end = nullptr; // Negative numbers aren't flags. ignore_result(strtod(argv[i+1], &end)); if (end == argv[i+1] && SkStrStartsWith(argv[i+1], '-')) { break; } i++; flag->append(argv[i]); } break; case SkFlagInfo::kInt_FlagType: i++; flag->setInt(atoi(argv[i])); break; case SkFlagInfo::kDouble_FlagType: i++; flag->setDouble(atof(argv[i])); break; default: SkDEBUGFAIL("Invalid flag type"); } } flag = flag->next(); } if (!matchedFlag) { #if defined(SK_BUILD_FOR_MAC) if (SkStrStartsWith(argv[i], "NSDocumentRevisions") || SkStrStartsWith(argv[i], "-NSDocumentRevisions")) { i++; // skip YES } else #endif if (FLAGS_undefok) { SkDebugf("FYI: ignoring unknown flag '%s'.\n", argv[i]); } else { SkDebugf("Got unknown flag '%s'. Exiting.\n", argv[i]); exit(-1); } } } } // Since all of the flags have been set, release the memory used by each // flag. FLAGS_x can still be used after this. SkFlagInfo* flag = gHead; gHead = nullptr; while (flag != nullptr) { SkFlagInfo* next = flag->next(); delete flag; flag = next; } if (helpPrinted) { exit(0); } }
void SkDisplayMath::executeFunction(SkDisplayable* target, int index, SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, SkScriptValue* scriptValue) { if (scriptValue == NULL) return; SkASSERT(target == this); SkScriptValue* array = parameters.begin(); SkScriptValue* end = parameters.end(); SkScalar input = parameters[0].fOperand.fScalar; SkScalar scalarResult; switch (index) { case SK_FUNCTION(abs): scalarResult = SkScalarAbs(input); break; case SK_FUNCTION(acos): scalarResult = SkScalarACos(input); break; case SK_FUNCTION(asin): scalarResult = SkScalarASin(input); break; case SK_FUNCTION(atan): scalarResult = SkScalarATan2(input, SK_Scalar1); break; case SK_FUNCTION(atan2): scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar); break; case SK_FUNCTION(ceil): scalarResult = SkScalarCeilToScalar(input); break; case SK_FUNCTION(cos): scalarResult = SkScalarCos(input); break; case SK_FUNCTION(exp): scalarResult = SkScalarExp(input); break; case SK_FUNCTION(floor): scalarResult = SkScalarFloorToScalar(input); break; case SK_FUNCTION(log): scalarResult = SkScalarLog(input); break; case SK_FUNCTION(max): scalarResult = -SK_ScalarMax; while (array < end) { scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(min): scalarResult = SK_ScalarMax; while (array < end) { scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(pow): // not the greatest -- but use x^y = e^(y * ln(x)) scalarResult = SkScalarLog(input); scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult); scalarResult = SkScalarExp(scalarResult); break; case SK_FUNCTION(random): scalarResult = fRandom.nextUScalar1(); break; case SK_FUNCTION(round): scalarResult = SkScalarRoundToScalar(input); break; case SK_FUNCTION(sin): scalarResult = SkScalarSin(input); break; case SK_FUNCTION(sqrt): { SkASSERT(parameters.count() == 1); SkASSERT(type == SkType_Float); scalarResult = SkScalarSqrt(input); } break; case SK_FUNCTION(tan): scalarResult = SkScalarTan(input); break; default: SkASSERT(0); scalarResult = SK_ScalarNaN; } scriptValue->fOperand.fScalar = scalarResult; scriptValue->fType = SkType_Float; }
/* Load info from a configuration file that populates the system/fallback font structures */ static void load_font_info() { SkTDArray<FontFamily*> fontFamilies; if (gTestMainConfigFile) { getTestFontFamilies(fontFamilies, gTestMainConfigFile, gTestFallbackConfigFile); } else { getFontFamilies(fontFamilies); } SkTDArray<FontInitRec> fontInfo; bool firstInFamily = false; for (int i = 0; i < fontFamilies.count(); ++i) { FontFamily *family = fontFamilies[i]; firstInFamily = true; for (int j = 0; j < family->fFileNames.count(); ++j) { FontInitRec fontInfoRecord; fontInfoRecord.fFileName = family->fFileNames[j]; if (j == 0) { if (family->fNames.count() == 0) { // Fallback font fontInfoRecord.fNames = (char **)gFBNames; } else { SkTDArray<const char*> names = family->fNames; const char **nameList = (const char**) malloc((names.count() + 1) * sizeof(char*)); if (nameList == NULL) { // shouldn't get here SkDEBUGFAIL("Failed to allocate nameList"); break; } if (gDefaultNames == NULL) { gDefaultNames = (char**) nameList; } for (int i = 0; i < names.count(); ++i) { nameList[i] = names[i]; } nameList[names.count()] = NULL; fontInfoRecord.fNames = nameList; } } else { fontInfoRecord.fNames = NULL; } *fontInfo.append() = fontInfoRecord; } } gNumSystemFonts = fontInfo.count(); gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec)); gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t)); if (gSystemFonts == NULL) { // shouldn't get here SkDEBUGFAIL("No system fonts were found"); gNumSystemFonts = 0; } #if SK_DEBUG_FONTS SkDebugf("---- We have %d system fonts", gNumSystemFonts); #endif for (size_t i = 0; i < gNumSystemFonts; ++i) { gSystemFonts[i].fFileName = fontInfo[i].fFileName; gSystemFonts[i].fNames = fontInfo[i].fNames; #if SK_DEBUG_FONTS SkDebugf("---- gSystemFonts[%d] fileName=%s", i, fontInfo[i].fFileName); #endif } fontFamilies.deleteAll(); }
SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr, int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical, bool firstPass) { SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, topLeft, unsortable, done, firstPass); if (!current) { return NULL; } const int startIndex = *indexPtr; const int endIndex = *endIndexPtr; if (*firstContour) { current->initWinding(startIndex, endIndex, angleIncludeType); *firstContour = false; return current; } int minIndex = SkMin32(startIndex, endIndex); int sumWinding = current->windSum(minIndex); if (sumWinding == SK_MinS32) { int index = endIndex; int oIndex = startIndex; do { const SkOpSpan& span = current->span(index); if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) { current->addSimpleAngle(index); } sumWinding = current->computeSum(oIndex, index, angleIncludeType); SkTSwap(index, oIndex); } while (sumWinding == SK_MinS32 && index == startIndex); } if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { return current; } int contourWinding; int oppContourWinding = 0; // the simple upward projection of the unresolved points hit unsortable angles // shoot rays at right angles to the segment to find its winding, ignoring angle cases bool tryAgain; double tHit; SkScalar hitDx = 0; SkScalar hitOppDx = 0; // keep track of subsequent returns to detect infinite loops SkTDArray<SortableTop> sortableTops; do { // if current is vertical, find another candidate which is not // if only remaining candidates are vertical, then they can be marked done SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); skipVertical(contourList, ¤t, indexPtr, endIndexPtr); SkASSERT(current); // FIXME: if null, all remaining are vertical SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); tryAgain = false; contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, &hitDx, &tryAgain, onlyVertical, false); if (tryAgain) { bool giveUp = false; int count = sortableTops.count(); for (int index = 0; index < count; ++index) { const SortableTop& prev = sortableTops[index]; if (giveUp) { prev.fSegment->markDoneFinal(prev.fIndex); } else if (prev.fSegment == current && (prev.fIndex == *indexPtr || prev.fEndIndex == *endIndexPtr)) { // remaining edges are non-vertical and cannot have their winding computed // mark them as done and return, and hope that assembly can fill the holes giveUp = true; index = -1; } } if (giveUp) { *done = true; return NULL; } } SortableTop* sortableTop = sortableTops.append(); sortableTop->fSegment = current; sortableTop->fIndex = *indexPtr; sortableTop->fEndIndex = *endIndexPtr; #if DEBUG_SORT SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=%d vert=%d\n", __FUNCTION__, current->debugID(), *indexPtr, *endIndexPtr, tHit, hitDx, tryAgain, *onlyVertical); #endif if (*onlyVertical) { return current; } if (tryAgain) { continue; } if (angleIncludeType < SkOpAngle::kBinarySingle) { break; } oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, &hitOppDx, &tryAgain, NULL, true); } while (tryAgain); bool success = current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx); if (current->done()) { return NULL; } else if (!success) { // check if the span has a valid winding int min = SkTMin(*indexPtr, *endIndexPtr); const SkOpSpan& span = current->span(min); if (span.fWindSum == SK_MinS32) { return NULL; } } return current; }
void SkCommandLineFlags::Parse(int argc, char** argv) { // Only allow calling this function once. static bool gOnce; if (gOnce) { SkDebugf("Parse should only be called once at the beginning of main!\n"); SkASSERT(false); return; } gOnce = true; bool helpPrinted = false; // Loop over argv, starting with 1, since the first is just the name of the program. for (int i = 1; i < argc; i++) { if (0 == strcmp("-h", argv[i]) || 0 == strcmp("--help", argv[i])) { // Print help message. SkTDArray<const char*> helpFlags; for (int j = i + 1; j < argc; j++) { if (SkStrStartsWith(argv[j], '-')) { break; } helpFlags.append(1, &argv[j]); } if (0 == helpFlags.count()) { // Only print general help message if help for specific flags is not requested. SkDebugf("%s\n%s\n", argv[0], gUsage.c_str()); } SkDebugf("Flags:\n"); SkFlagInfo* flag = SkCommandLineFlags::gHead; while (flag != NULL) { // If no flags followed --help, print them all bool printFlag = 0 == helpFlags.count(); if (!printFlag) { for (int k = 0; k < helpFlags.count(); k++) { if (flag->name().equals(helpFlags[k]) || flag->shortName().equals(helpFlags[k])) { printFlag = true; helpFlags.remove(k); break; } } } if (printFlag) { print_help_for_flag(flag); } flag = flag->next(); } if (helpFlags.count() > 0) { SkDebugf("Requested help for unrecognized flags:\n"); for (int k = 0; k < helpFlags.count(); k++) { SkDebugf("\t--%s\n", helpFlags[k]); } } helpPrinted = true; } if (!helpPrinted) { bool flagMatched = false; SkFlagInfo* flag = gHead; while (flag != NULL) { if (flag->match(argv[i])) { flagMatched = true; switch (flag->getFlagType()) { case SkFlagInfo::kBool_FlagType: // Can be handled by match, above, but can also be set by the next // string. if (i+1 < argc && !SkStrStartsWith(argv[i+1], '-')) { i++; bool value; if (parse_bool_arg(argv[i], &value)) { flag->setBool(value); } } break; case SkFlagInfo::kString_FlagType: flag->resetStrings(); // Add all arguments until another flag is reached. while (i+1 < argc && !SkStrStartsWith(argv[i+1], '-')) { i++; flag->append(argv[i]); } break; case SkFlagInfo::kInt_FlagType: i++; flag->setInt(atoi(argv[i])); break; case SkFlagInfo::kDouble_FlagType: i++; flag->setDouble(atof(argv[i])); break; default: SkDEBUGFAIL("Invalid flag type"); } break; } flag = flag->next(); } if (!flagMatched) { SkString stripped(argv[i]); while (stripped.startsWith('-')) { stripped.remove(0, 1); } if (!FLAGS_undefok.contains(stripped.c_str())) { SkDebugf("Got unknown flag \"%s\". Exiting.\n", argv[i]); exit(-1); } } } } // Since all of the flags have been set, release the memory used by each // flag. FLAGS_x can still be used after this. SkFlagInfo* flag = gHead; gHead = NULL; while (flag != NULL) { SkFlagInfo* next = flag->next(); SkDELETE(flag); flag = next; } if (helpPrinted) { exit(0); } }
void SkpSkGrThreadedTestRunner::render() { SkTaskGroup().batch(fRunnables.count(), [&](int i) { fRunnables[i](); }); }
int dm_main() { SetupCrashHandler(); SkAutoGraphics ag; SkTaskGroup::Enabler enabled(FLAGS_threads); if (FLAGS_leaks) { SkInstCountPrintLeaksOnExit(); } start_keepalive(); gather_gold(); gather_uninteresting_hashes(); gather_srcs(); gather_sinks(); gather_tests(); gPending = gSrcs.count() * gSinks.count() + gThreadedTests.count() + gGPUTests.count(); SkDebugf("%d srcs * %d sinks + %d tests == %d tasks\n", gSrcs.count(), gSinks.count(), gThreadedTests.count() + gGPUTests.count(), gPending); // We try to exploit as much parallelism as is safe. Most Src/Sink pairs run on any thread, // but Sinks that identify as part of a particular enclave run serially on a single thread. // CPU tests run on any thread. GPU tests depend on --gpu_threading. SkTArray<Task> enclaves[kNumEnclaves]; for (int j = 0; j < gSinks.count(); j++) { SkTArray<Task>& tasks = enclaves[gSinks[j]->enclave()]; for (int i = 0; i < gSrcs.count(); i++) { tasks.push_back(Task(gSrcs[i], gSinks[j])); } } SkTaskGroup tg; tg.batch(run_test, gThreadedTests.begin(), gThreadedTests.count()); for (int i = 0; i < kNumEnclaves; i++) { switch(i) { case kAnyThread_Enclave: tg.batch(Task::Run, enclaves[i].begin(), enclaves[i].count()); break; case kGPU_Enclave: tg.add(run_enclave_and_gpu_tests, &enclaves[i]); break; default: tg.add(run_enclave, &enclaves[i]); break; } } tg.wait(); // At this point we're back in single-threaded land. SkDebugf("\n"); if (gFailures.count() > 0) { SkDebugf("Failures:\n"); for (int i = 0; i < gFailures.count(); i++) { SkDebugf("\t%s\n", gFailures[i].c_str()); } SkDebugf("%d failures\n", gFailures.count()); return 1; } if (gPending > 0) { SkDebugf("Hrm, we didn't seem to run everything we intended to! Please file a bug.\n"); return 1; } return 0; }
DEF_TEST(BitSet, reporter) { SkBitSet set0(65536); REPORTER_ASSERT(reporter, set0.isBitSet(0) == false); REPORTER_ASSERT(reporter, set0.isBitSet(32767) == false); REPORTER_ASSERT(reporter, set0.isBitSet(65535) == false); SkBitSet set1(65536); REPORTER_ASSERT(reporter, set0 == set1); set0.setBit(22, true); REPORTER_ASSERT(reporter, set0.isBitSet(22) == true); set0.setBit(24, true); REPORTER_ASSERT(reporter, set0.isBitSet(24) == true); set0.setBit(35, true); // on a different DWORD REPORTER_ASSERT(reporter, set0.isBitSet(35) == true); set0.setBit(22, false); REPORTER_ASSERT(reporter, set0.isBitSet(22) == false); REPORTER_ASSERT(reporter, set0.isBitSet(24) == true); REPORTER_ASSERT(reporter, set0.isBitSet(35) == true); SkTDArray<unsigned int> data; set0.exportTo(&data); REPORTER_ASSERT(reporter, data.count() == 2); REPORTER_ASSERT(reporter, data[0] == 24); REPORTER_ASSERT(reporter, data[1] == 35); set1.setBit(12345, true); set1.orBits(set0); REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false); REPORTER_ASSERT(reporter, set1.isBitSet(12345) == true); REPORTER_ASSERT(reporter, set1.isBitSet(22) == false); REPORTER_ASSERT(reporter, set1.isBitSet(24) == true); REPORTER_ASSERT(reporter, set0.isBitSet(35) == true); REPORTER_ASSERT(reporter, set1 != set0); set1.clearAll(); REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false); REPORTER_ASSERT(reporter, set1.isBitSet(12345) == false); REPORTER_ASSERT(reporter, set1.isBitSet(22) == false); REPORTER_ASSERT(reporter, set1.isBitSet(24) == false); REPORTER_ASSERT(reporter, set1.isBitSet(35) == false); set1.orBits(set0); REPORTER_ASSERT(reporter, set1 == set0); SkBitSet set2(1); SkBitSet set3(1); SkBitSet set4(4); SkBitSet set5(33); REPORTER_ASSERT(reporter, set2 == set3); REPORTER_ASSERT(reporter, set2 != set4); REPORTER_ASSERT(reporter, set2 != set5); set2.setBit(0, true); REPORTER_ASSERT(reporter, set2 != set5); set5.setBit(0, true); REPORTER_ASSERT(reporter, set2 != set5); REPORTER_ASSERT(reporter, set2 != set3); set3.setBit(0, true); REPORTER_ASSERT(reporter, set2 == set3); set3.clearAll(); set3 = set2; set2 = set2; REPORTER_ASSERT(reporter, set2 == set3); }
void SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) { SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage); for (int i = 0; i < targetList->count(); ++i) { (*targetList)[i]->emit(stream, this, true); } }
// static void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages, SkPDFCatalog* catalog, SkTDArray<SkPDFDict*>* pageTree, SkPDFDict** rootNode) { // PDF wants a tree describing all the pages in the document. We arbitrary // choose 8 (kNodeSize) as the number of allowed children. The internal // nodes have type "Pages" with an array of children, a parent pointer, and // the number of leaves below the node as "Count." The leaves are passed // into the method, have type "Page" and need a parent pointer. This method // builds the tree bottom up, skipping internal nodes that would have only // one child. static const int kNodeSize = 8; SkAutoTUnref<SkPDFName> kidsName(new SkPDFName("Kids")); SkAutoTUnref<SkPDFName> countName(new SkPDFName("Count")); SkAutoTUnref<SkPDFName> parentName(new SkPDFName("Parent")); // curNodes takes a reference to its items, which it passes to pageTree. SkTDArray<SkPDFDict*> curNodes; curNodes.setReserve(pages.count()); for (int i = 0; i < pages.count(); i++) { SkSafeRef(pages[i]); curNodes.push(pages[i]); } // nextRoundNodes passes its references to nodes on to curNodes. SkTDArray<SkPDFDict*> nextRoundNodes; nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); int treeCapacity = kNodeSize; do { for (int i = 0; i < curNodes.count(); ) { if (i > 0 && i + 1 == curNodes.count()) { nextRoundNodes.push(curNodes[i]); break; } SkPDFDict* newNode = new SkPDFDict("Pages"); SkAutoTUnref<SkPDFObjRef> newNodeRef(new SkPDFObjRef(newNode)); SkAutoTUnref<SkPDFArray> kids(new SkPDFArray); kids->reserve(kNodeSize); int count = 0; for (; i < curNodes.count() && count < kNodeSize; i++, count++) { curNodes[i]->insert(parentName.get(), newNodeRef.get()); kids->append(new SkPDFObjRef(curNodes[i]))->unref(); // TODO(vandebo): put the objects in strict access order. // Probably doesn't matter because they are so small. if (curNodes[i] != pages[0]) { pageTree->push(curNodes[i]); // Transfer reference. catalog->addObject(curNodes[i], false); } else { SkSafeUnref(curNodes[i]); catalog->addObject(curNodes[i], true); } } // treeCapacity is the number of leaf nodes possible for the // current set of subtrees being generated. (i.e. 8, 64, 512, ...). // It is hard to count the number of leaf nodes in the current // subtree. However, by construction, we know that unless it's the // last subtree for the current depth, the leaf count will be // treeCapacity, otherwise it's what ever is left over after // consuming treeCapacity chunks. int pageCount = treeCapacity; if (i == curNodes.count()) { pageCount = ((pages.count() - 1) % treeCapacity) + 1; } newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); newNode->insert(kidsName.get(), kids.get()); nextRoundNodes.push(newNode); // Transfer reference. } curNodes = nextRoundNodes; nextRoundNodes.rewind(); treeCapacity *= kNodeSize; } while (curNodes.count() > 1); pageTree->push(curNodes[0]); // Transfer reference. catalog->addObject(curNodes[0], false); if (rootNode) { *rootNode = curNodes[0]; } }
static FamilyRec* find_familyrec(const char name[]) { const NameFamilyPair* list = gNameList.begin(); int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name, sizeof(list[0])); return index >= 0 ? list[index].fFamily : NULL; }
bool SampleWindow::nextSample() { fCurrIndex = (fCurrIndex + 1) % fSamples.count(); this->loadView(fSamples[fCurrIndex]()); return true; }
void GrLayerHoister::DrawLayers(const SkTDArray<GrHoistedLayer>& atlased, const SkTDArray<GrHoistedLayer>& nonAtlased, const SkTDArray<GrHoistedLayer>& recycled, GrReplacements* replacements) { // Render the atlased layers that require it if (atlased.count() > 0) { // All the atlased layers are rendered into the same GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( atlased[0].fLayer->texture()->asRenderTarget(), NULL)); SkCanvas* atlasCanvas = surface->getCanvas(); SkPaint paint; paint.setColor(SK_ColorTRANSPARENT); paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref(); for (int i = 0; i < atlased.count(); ++i) { GrCachedLayer* layer = atlased[i].fLayer; const SkPicture* pict = atlased[i].fPicture; const SkIPoint offset = atlased[i].fOffset; atlasCanvas->save(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), SkIntToScalar(layer->rect().fTop), SkIntToScalar(layer->rect().width()), SkIntToScalar(layer->rect().height())); atlasCanvas->clipRect(bound); // Since 'clear' doesn't respect the clip we need to draw a rect // TODO: ensure none of the atlased layers contain a clear call! atlasCanvas->drawRect(bound, paint); // info.fCTM maps the layer's top/left to the origin. // Since this layer is atlased, the top/left corner needs // to be offset to the correct location in the backing texture. SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); initialCTM.postTranslate(bound.fLeft, bound.fTop); atlasCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); atlasCanvas->translate(bound.fLeft, bound.fTop); atlasCanvas->concat(atlased[i].fCTM); SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound, layer->start()+1, layer->stop(), initialCTM); atlasCanvas->restore(); } atlasCanvas->flush(); } // Render the non-atlased layers that require it for (int i = 0; i < nonAtlased.count(); ++i) { GrCachedLayer* layer = nonAtlased[i].fLayer; const SkPicture* pict = nonAtlased[i].fPicture; const SkIPoint offset = nonAtlased[i].fOffset; // Each non-atlased layer has its own GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( layer->texture()->asRenderTarget(), NULL)); SkCanvas* layerCanvas = surface->getCanvas(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), SkIntToScalar(layer->rect().fTop), SkIntToScalar(layer->rect().width()), SkIntToScalar(layer->rect().height())); layerCanvas->clipRect(bound); // TODO: still useful? layerCanvas->clear(SK_ColorTRANSPARENT); SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); layerCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); layerCanvas->concat(nonAtlased[i].fCTM); SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound, layer->start()+1, layer->stop(), initialCTM); layerCanvas->flush(); } convert_layers_to_replacements(atlased, replacements); convert_layers_to_replacements(nonAtlased, replacements); convert_layers_to_replacements(recycled, replacements); }
void onDraw(SkCanvas* canvas) override { // We don't create pixels in an onOnceBeforeDraw() override because we want access to // GrContext. GrContext* context = canvas->getGrContext(); #if SK_SUPPORT_GPU // Workaround for SampleApp. if (GrTexture* tex = fBigTestPixels.fBitmap.getTexture()) { if (tex->wasDestroyed()) { fCreatedPixels = false; } } #endif bool madePixels = fCreatedPixels; if (!madePixels) { madePixels = gBleedRec[fBT].fPixelMaker(context, &fSmallTestPixels, kSmallTextureSize, kSmallTextureSize); madePixels &= gBleedRec[fBT].fPixelMaker(context, &fBigTestPixels, 2 * kMaxTileSize, 2 * kMaxTileSize); fCreatedPixels = madePixels; } // Assume that if we coulnd't make the bitmap/image it's because it's a GPU test on a // non-GPU backend. if (!madePixels) { skiagm::GM::DrawGpuOnlyMessage(canvas); return; } fShader = gBleedRec[fBT].fShaderMaker(); canvas->clear(SK_ColorGRAY); SkTDArray<SkMatrix> matrices; // Draw with identity *matrices.append() = SkMatrix::I(); // Draw with rotation and scale down in x, up in y. SkMatrix m; static const SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing); m.setTranslate(0, kBottom); m.preRotate(15.f, 0, kBottom + kBlockSpacing); m.preScale(0.71f, 1.22f); *matrices.append() = m; // Align the next set with the middle of the previous in y, translated to the right in x. SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} }; matrices[matrices.count()-1].mapPoints(corners, 4); SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4; SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX), SkTMax(corners[2].fX, corners[3].fX)); m.setTranslate(x, y); m.preScale(0.2f, 0.2f); *matrices.append() = m; SkScalar maxX = 0; for (int antiAlias = 0; antiAlias < 2; ++antiAlias) { canvas->save(); canvas->translate(maxX, 0); for (int m = 0; m < matrices.count(); ++m) { canvas->save(); canvas->concat(matrices[m]); bool aa = SkToBool(antiAlias); // First draw a column with no bleeding and no filtering this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality); // Then draw a column with no bleeding and low filtering this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality); // Then draw a column with no bleeding and high filtering this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality); // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur) this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality); // Then draw a column with bleeding and low filtering this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality); // Finally draw a column with bleeding and high filtering this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality); SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } }; matrices[m].mapPoints(corners, 4); SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX), SkTMax(corners[2].fX, corners[3].fX)); maxX = SkTMax(maxX, x); canvas->restore(); } canvas->restore(); } }