Exemple #1
0
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;
}
Exemple #2
0
void TestRunner::render() {
    SkTaskGroup tg;
    for (int index = 0; index < fRunnables.count(); ++ index) {
        tg.add(fRunnables[index]);
    }
}
Exemple #3
0
    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();
        }
    }
Exemple #4
0
    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]));
    }
}
Exemple #6
0
// 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]);
    }
}
Exemple #7
0
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
            }
        }
    }
}
Exemple #8
0
    /*
        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
}
Exemple #9
0
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;
}
Exemple #10
0
 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;
 }
Exemple #11
0
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;
}
Exemple #12
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;
}
Exemple #15
0
/*  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();
}
Exemple #16
0
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, &current, indexPtr, endIndexPtr);
        SkASSERT(current);  // FIXME: if null, all remaining are vertical
        SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
        tryAgain = false;
        contourWinding = rightAngleWinding(contourList, &current, 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, &current, 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);
    }
}
Exemple #18
0
void SkpSkGrThreadedTestRunner::render() {
    SkTaskGroup().batch(fRunnables.count(), [&](int i) {
        fRunnables[i]();
    });
}
Exemple #19
0
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;
}
Exemple #20
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);
}
Exemple #21
0
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);
    }
}
Exemple #22
0
// 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;
}
Exemple #24
0
bool SampleWindow::nextSample() {
    fCurrIndex = (fCurrIndex + 1) % fSamples.count();
    this->loadView(fSamples[fCurrIndex]());
    return true;
}
Exemple #25
0
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);
}
Exemple #26
0
    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();
        }
    }