Example #1
0
bool
SkFontManager::savePreData()
{
    SkStream * inStream = openReadStream( SYSTEM_DL_PREDATA_FILE );
    SkFILEWStream * outStream = NULL;
    preDataHeader header = { 1, __key(), 0 };
    SkString permission;

    if( !inStream )
    {
        setUpdateVersion( 2 );
        header.updateVersion++;
        header.count = mDownloadFonts.numFonts();
        goto SAVE0;
    }
    else
    {
        inStream->read( &header, SYSTEM_DL_PREDATA_HEADER_LEN );

        if( header.tag != __key() )
        {
            header.updateVersion = 1;
            header.tag = __key();
            header.count = mDownloadFonts.numFonts();
            goto SAVE1;
        }

        header.count = mDownloadFonts.numFonts();
        header.updateVersion++;
        if( header.updateVersion >= 0xFFFFFFFE )
            header.updateVersion = 2;
    }

SAVE1:
    SkDELETE( inStream );
    inStream = NULL;

SAVE0:
    outStream = openWriteStream( SYSTEM_DL_PREDATA_FILE );

    if( !outStream )
    {
        if( permission_denied() )
            goto SKIP_ERROR0;
        HyLogef( "outStream is null" );
        goto ERROR0;
    }

    outStream->write( &header, SYSTEM_DL_PREDATA_HEADER_LEN );

    for( uint32_t n = 0 ; n < header.count ; n++ )
    {
        SkFontData * font = mDownloadFonts.getFont( n );
        font->writePreData( outStream );
    }

    SkDELETE( outStream );
    outStream = NULL;

    //setUpdateVersion( header.updateVersion );

    permission.set( SYSTEM_FONT_PERMISSION_SET );
    permission.append( SYSTEM_DL_PREDATA_FILE );
    system( permission.c_str() );

    HyLogi( "Font Configuration Data (%d), saved.", header.updateVersion );
    return true;

SKIP_ERROR0:
    return false;

ERROR0:
    if( outStream )
        SkDELETE( outStream );
    return false;
}
void PictureBenchmark::run(SkPicture* pict) {
    SkASSERT(pict);
    if (NULL == pict) {
        return;
    }

    SkASSERT(fRenderer != NULL);
    if (NULL == fRenderer) {
        return;
    }

    fRenderer->init(pict);

    // We throw this away to remove first time effects (such as paging in this program)
    fRenderer->setup();
    fRenderer->render(NULL);
    fRenderer->resetState(true);

    bool usingGpu = false;
#if SK_SUPPORT_GPU
    usingGpu = fRenderer->isUsingGpuDevice();
#endif

    uint32_t timerTypes = fTimerTypes;
    if (!usingGpu) {
        timerTypes &= ~TimerData::kGpu_Flag;
    }

    SkString timeFormat;
    if (TimerData::kPerIter_Result == fTimerResult) {
        timeFormat = fRenderer->getPerIterTimeFormat();
    } else {
        timeFormat = fRenderer->getNormalTimeFormat();
    }

    if (fTimeIndividualTiles) {
        TiledPictureRenderer* tiledRenderer = fRenderer->getTiledRenderer();
        SkASSERT(tiledRenderer && tiledRenderer->supportsTimingIndividualTiles());
        if (NULL == tiledRenderer || !tiledRenderer->supportsTimingIndividualTiles()) {
            return;
        }
        int xTiles, yTiles;
        if (!tiledRenderer->tileDimensions(xTiles, yTiles)) {
            return;
        }

        // Insert a newline so that each tile is reported on its own line (separate from the line
        // that describes the skp being run).
        this->logProgress("\n");

        int x, y;
        while (tiledRenderer->nextTile(x, y)) {
            // There are two timers, which will behave slightly differently:
            // 1) longRunningTimer, along with perTileTimerData, will time how long it takes to draw
            // one tile fRepeats times, and take the average. As such, it will not respect thea
            // logPerIter or printMin options, since it does not know the time per iteration. It
            // will also be unable to call flush() for each tile.
            // The goal of this timer is to make up for a system timer that is not precise enough to
            // measure the small amount of time it takes to draw one tile once.
            //
            // 2) perTileTimer, along with perTileTimerData, will record each run separately, and
            // then take the average. As such, it supports logPerIter and printMin options.
            //
            // Although "legal", having two gpu timers running at the same time
            // seems to cause problems (i.e., INVALID_OPERATIONs) on several
            // platforms. To work around this, we disable the gpu timer on the
            // long running timer.
            SkAutoTDelete<BenchTimer> longRunningTimer(this->setupTimer());
            TimerData longRunningTimerData(1);
            SkAutoTDelete<BenchTimer> perTileTimer(this->setupTimer(false));
            TimerData perTileTimerData(fRepeats);
            longRunningTimer->start();
            for (int i = 0; i < fRepeats; ++i) {
                perTileTimer->start();
                tiledRenderer->drawCurrentTile();
                perTileTimer->truncatedEnd();
                tiledRenderer->resetState(false);
                perTileTimer->end();
                SkAssertResult(perTileTimerData.appendTimes(perTileTimer.get()));
            }
            longRunningTimer->truncatedEnd();
            tiledRenderer->resetState(true);
            longRunningTimer->end();
            SkAssertResult(longRunningTimerData.appendTimes(longRunningTimer.get()));

            SkString configName = tiledRenderer->getConfigName();
            configName.appendf(": tile [%i,%i] out of [%i,%i]", x, y, xTiles, yTiles);

            SkString result = perTileTimerData.getResult(timeFormat.c_str(), fTimerResult,
                                                         configName.c_str(), timerTypes);
            result.append("\n");

// TODO(borenet): Turn off per-iteration tile time reporting for now.  Avoiding logging the time
// for every iteration for each tile cuts down on data file size by a significant amount. Re-enable
// this once we're loading the bench data directly into a data store and are no longer generating
// SVG graphs.
#if 0
            this->logProgress(result.c_str());
#endif

            configName.append(" <averaged>");
            SkString longRunningResult = longRunningTimerData.getResult(
                tiledRenderer->getNormalTimeFormat().c_str(),
                TimerData::kAvg_Result,
                configName.c_str(), timerTypes, fRepeats);
            longRunningResult.append("\n");
            this->logProgress(longRunningResult.c_str());
        }
    } else {
        SkAutoTDelete<BenchTimer> timer(this->setupTimer());
        TimerData timerData(fRepeats);
        for (int i = 0; i < fRepeats; ++i) {
            fRenderer->setup();

            timer->start();
            fRenderer->render(NULL);
            timer->truncatedEnd();

            // Finishes gl context
            fRenderer->resetState(true);
            timer->end();

            SkAssertResult(timerData.appendTimes(timer.get()));
        }

        SkString configName = fRenderer->getConfigName();

        SkString result = timerData.getResult(timeFormat.c_str(),
                                              fTimerResult,
                                              configName.c_str(),
                                              timerTypes);
        result.append("\n");
        this->logProgress(result.c_str());
    }

    fRenderer->end();
}
Example #3
0
SkString* SkObjectParser::BitmapToString(const SkBitmap& bitmap) {
    SkString* mBitmap = new SkString("SkBitmap: ");
    mBitmap->append("W: ");
    mBitmap->appendS32(bitmap.width());
    mBitmap->append(" H: ");
    mBitmap->appendS32(bitmap.height());

    const char* gColorTypeStrings[] = {
        "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8", "G8", "RGBAf16"
    };
    static_assert(kLastEnum_SkColorType + 1 == SK_ARRAY_COUNT(gColorTypeStrings),
                  "colortype names do not match colortype enum");

    mBitmap->append(" ColorType: ");
    mBitmap->append(gColorTypeStrings[bitmap.colorType()]);

    if (bitmap.isOpaque()) {
        mBitmap->append(" opaque");
    } else {
        mBitmap->append(" not-opaque");
    }

    if (bitmap.isImmutable()) {
        mBitmap->append(" immutable");
    } else {
        mBitmap->append(" not-immutable");
    }

    if (bitmap.isVolatile()) {
        mBitmap->append(" volatile");
    } else {
        mBitmap->append(" not-volatile");
    }

    mBitmap->append(" genID: ");
    mBitmap->appendS32(bitmap.getGenerationID());

    return mBitmap;
}
static void draw_zero_length_capped_paths_dbl_contour(SkCanvas* canvas, bool aa) {
    canvas->translate(kCellPad, kCellPad);

    SkImageInfo info = canvas->imageInfo().makeWH(kCellWidth, kCellHeight);
    auto surface = canvas->makeSurface(info);
    if (!surface) {
        surface = SkSurface::MakeRasterN32Premul(kCellWidth, kCellHeight);
    }

    SkPaint paint;
    paint.setColor(SK_ColorWHITE);
    paint.setAntiAlias(aa);
    paint.setStyle(SkPaint::kStroke_Style);

    int numFailedTests = 0;
    for (auto cap : kCaps) {
        for (auto width : kWidths) {
            paint.setStrokeCap(cap);
            paint.setStrokeWidth(width);
            canvas->save();

            for (auto firstVerb : kSomeVerbs) {
                for (auto secondVerb : kSomeVerbs) {
                    int expectedCaps = 0;

                    SkString pathStr;
                    pathStr.append("M 9.5 9.5 ");
                    if (firstVerb) {
                        pathStr.append(firstVerb);
                        ++expectedCaps;
                    }
                    pathStr.append("M 40.5 9.5 ");
                    if (secondVerb) {
                        pathStr.append(secondVerb);
                        ++expectedCaps;
                    }

                    SkPath path;
                    SkParsePath::FromSVGString(pathStr.c_str(), &path);

                    surface->getCanvas()->clear(SK_ColorTRANSPARENT);
                    surface->getCanvas()->drawPath(path, paint);
                    auto img = surface->makeImageSnapshot();

                    if (SkPaint::kButt_Cap == cap) {
                        expectedCaps = 0;
                    }

                    if (!draw_path_cell(canvas, img.get(), expectedCaps)) {
                        ++numFailedTests;
                    }
                    canvas->translate(kCellWidth + kCellPad, 0);
                }
            }
            canvas->restore();
            canvas->translate(0, kCellHeight + kCellPad);
        }
    }

    canvas->drawColor(numFailedTests > 0 ? kFailureRed : kSuccessGreen);
}
Example #5
0
void SkDebugger::getOverviewText(const SkTDArray<double>* typeTimes,
                                 double totTime,
                                 SkString* overview,
                                 int numRuns) {
    const SkTDArray<SkDrawCommand*>& commands = this->getDrawCommands();

    SkTDArray<int> counts;
    counts.setCount(LAST_DRAWTYPE_ENUM+1);
    for (int i = 0; i < LAST_DRAWTYPE_ENUM+1; ++i) {
        counts[i] = 0;
    }

    for (int i = 0; i < commands.count(); i++) {
        counts[commands[i]->getType()]++;
    }

    overview->reset();
    int total = 0;
#ifdef SK_DEBUG
    double totPercent = 0, tempSum = 0;
#endif
    for (int i = 0; i < LAST_DRAWTYPE_ENUM+1; ++i) {
        if (0 == counts[i]) {
            // if there were no commands of this type then they should've consumed no time
            SkASSERT(NULL == typeTimes || 0.0 == (*typeTimes)[i]);
            continue;
        }

        overview->append(SkDrawCommand::GetCommandString((DrawType) i));
        overview->append(": ");
        overview->appendS32(counts[i]);
        if (NULL != typeTimes && totTime >= 0.0) {
            overview->append(" - ");
            overview->appendf("%.2f", (*typeTimes)[i]/(float)numRuns);
            overview->append("ms");
            overview->append(" - ");
            double percent = 100.0*(*typeTimes)[i]/totTime;
            overview->appendf("%.2f", percent);
            overview->append("%");
#ifdef SK_DEBUG
            totPercent += percent;
            tempSum += (*typeTimes)[i];
#endif
        }
        overview->append("<br/>");
        total += counts[i];
    }
#ifdef SK_DEBUG
    if (NULL != typeTimes) {
        SkASSERT(SkScalarNearlyEqual(SkDoubleToScalar(totPercent),
                                     SkDoubleToScalar(100.0)));
        SkASSERT(SkScalarNearlyEqual(SkDoubleToScalar(tempSum),
                                     SkDoubleToScalar(totTime)));
    }
#endif

    if (totTime > 0.0) {
        overview->append("Total Time: ");
        overview->appendf("%.2f", totTime/(float)numRuns);
        overview->append("ms");
#ifdef SK_DEBUG
        overview->append(" ");
        overview->appendScalar(SkDoubleToScalar(totPercent));
        overview->append("% ");
#endif
        overview->append("<br/>");
    }

    SkString totalStr;
    totalStr.append("Total Draw Commands: ");
    totalStr.appendScalar(SkDoubleToScalar(total));
    totalStr.append("<br/>");
    overview->insert(0, totalStr);

    overview->append("<br/>");
    overview->append("SkPicture Width: ");
    overview->appendS32(pictureWidth());
    overview->append("px<br/>");
    overview->append("SkPicture Height: ");
    overview->appendS32(pictureHeight());
    overview->append("px");
}
void GrGLConvolutionEffect::emitCode(EmitArgs& args) {
    const GrConvolutionEffect& ce = args.fFp.cast<GrConvolutionEffect>();

    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                    kVec2f_GrSLType, kDefault_GrSLPrecision,
                                                    "ImageIncrement");
    if (ce.useBounds()) {
        fBoundsUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                kVec2f_GrSLType, kDefault_GrSLPrecision,
                                                "Bounds");
    }

    int width = Gr1DKernelEffect::WidthFromRadius(ce.radius());

    int arrayCount = (width + 3) / 4;
    SkASSERT(4 * arrayCount >= width);

    fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
                                                 kVec4f_GrSLType, kDefault_GrSLPrecision,
                                                 "Kernel", arrayCount);

    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);

    fragBuilder->codeAppendf("%s = vec4(0, 0, 0, 0);", args.fOutputColor);

    const GrGLSLShaderVar& kernel = uniformHandler->getUniformVariable(fKernelUni);
    const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);

    fragBuilder->codeAppendf("vec2 coord = %s - %d.0 * %s;", coords2D.c_str(), ce.radius(), imgInc);

    // Manually unroll loop because some drivers don't; yields 20-30% speedup.
    const char* kVecSuffix[4] = { ".x", ".y", ".z", ".w" };
    for (int i = 0; i < width; i++) {
        SkString index;
        SkString kernelIndex;
        index.appendS32(i/4);
        kernel.appendArrayAccess(index.c_str(), &kernelIndex);
        kernelIndex.append(kVecSuffix[i & 0x3]);

        if (ce.useBounds()) {
            // We used to compute a bool indicating whether we're in bounds or not, cast it to a
            // float, and then mul weight*texture_sample by the float. However, the Adreno 430 seems
            // to have a bug that caused corruption.
            const char* bounds = uniformHandler->getUniformCStr(fBoundsUni);
            const char* component = ce.direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x";
            fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {",
                                     component, bounds, component, bounds);
        }
        fragBuilder->codeAppendf("\t\t%s += ", args.fOutputColor);
        fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord");
        fragBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str());
        if (ce.useBounds()) {
            fragBuilder->codeAppend("}");
        }
        fragBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc);
    }

    SkString modulate;
    GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
    fragBuilder->codeAppend(modulate.c_str());
}
Example #7
0
SkString* SkObjectParser::ScalarToString(SkScalar x, const char* text) {
    SkString* mScalar = new SkString(text);
    mScalar->append(" ");
    mScalar->appendScalar(x);
    return mScalar;
}
void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
    SkASSERT(kVertex_GrShaderFlag == visibility ||
             kGeometry_GrShaderFlag == visibility ||
             kFragment_GrShaderFlag == visibility);

    for (int i = 0; i < fSamplers.count(); ++i) {
        const UniformInfo& sampler = fSamplers[i];
        SkASSERT(sampler.fVariable.getType() == kTexture2DSampler_GrSLType);
        if (visibility == sampler.fVisibility) {
            sampler.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
            out->append(";\n");
        }
    }

    for (int i = 0; i < fTexelBuffers.count(); ++i) {
        const UniformInfo& texelBuffer = fTexelBuffers[i];
        if (visibility == texelBuffer.fVisibility) {
            texelBuffer.fVariable.appendDecl(fProgramBuilder->shaderCaps(), out);
            out->append(";\n");
        }
    }

#ifdef SK_DEBUG
    bool firstGeomOffsetCheck = false;
    bool firstFragOffsetCheck = false;
    for (int i = 0; i < fUniforms.count(); ++i) {
        const UniformInfo& localUniform = fUniforms[i];
        if (kVertex_GrShaderFlag == localUniform.fVisibility ||
            kGeometry_GrShaderFlag == localUniform.fVisibility ||
            (kVertex_GrShaderFlag | kGeometry_GrShaderFlag) == localUniform.fVisibility) {
            if (!firstGeomOffsetCheck) {
                // Check to make sure we are starting our offset at 0 so the offset qualifier we
                // set on each variable in the uniform block is valid.
                SkASSERT(0 == localUniform.fUBOffset);
                firstGeomOffsetCheck = true;
            }
        } else {
            SkASSERT(kFragment_GrShaderFlag == localUniform.fVisibility);
            if (!firstFragOffsetCheck) {
                // Check to make sure we are starting our offset at 0 so the offset qualifier we
                // set on each variable in the uniform block is valid.
                SkASSERT(0 == localUniform.fUBOffset);
                firstFragOffsetCheck = true;
            }
        }
    }
#endif

    SkString uniformsString;
    for (int i = 0; i < fUniforms.count(); ++i) {
        const UniformInfo& localUniform = fUniforms[i];
        if (visibility & localUniform.fVisibility) {
            if (GrSLTypeIsFloatType(localUniform.fVariable.getType())) {
                localUniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString);
                uniformsString.append(";\n");
            }
        }
    }

    if (!uniformsString.isEmpty()) {
        uint32_t uniformBinding;
        const char* stage;
        if (kVertex_GrShaderFlag == visibility) {
            uniformBinding = kGeometryBinding;
            stage = "vertex";
        } else if (kGeometry_GrShaderFlag == visibility) {
            uniformBinding = kGeometryBinding;
            stage = "geometry";
        } else {
            SkASSERT(kFragment_GrShaderFlag == visibility);
            uniformBinding = kFragBinding;
            stage = "fragment";
        }
        out->appendf("layout (set=%d, binding=%d) uniform %sUniformBuffer\n{\n",
                     kUniformBufferDescSet, uniformBinding, stage);
        out->appendf("%s\n};\n", uniformsString.c_str());
    }
}
Example #9
0
static bool dump_png(SkBitmap bitmap, const char* path, const char* md5) {
    const int w = bitmap.width(),
              h = bitmap.height();

    // First get the bitmap into N32 color format.  The next step will work only there.
    if (bitmap.colorType() != kN32_SkColorType) {
        SkBitmap n32;
        if (!bitmap.copyTo(&n32, kN32_SkColorType)) {
            return false;
        }
        bitmap = n32;
    }

    // Convert our N32 bitmap into unpremul RGBA for libpng.
    SkAutoTMalloc<uint32_t> rgba(w*h);
    if (!bitmap.readPixels(SkImageInfo::Make(w,h, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType),
                           rgba, 4*w, 0,0)) {
        return false;
    }

    // We don't need bitmap anymore.  Might as well drop our ref.
    bitmap.reset();

    FILE* f = fopen(path, "wb");
    if (!f) { return false; }

    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png) {
        fclose(f);
        return false;
    }

    png_infop info = png_create_info_struct(png);
    if (!info) {
        png_destroy_write_struct(&png, &info);
        fclose(f);
        return false;
    }

    SkString description;
    description.append("Key: ");
    for (int i = 0; i < FLAGS_key.count(); i++) {
        description.appendf("%s ", FLAGS_key[i]);
    }
    description.append("Properties: ");
    for (int i = 0; i < FLAGS_properties.count(); i++) {
        description.appendf("%s ", FLAGS_properties[i]);
    }
    description.appendf("MD5: %s", md5);

    png_text text[2];
    text[0].key = (png_charp)"Author";
    text[0].text = (png_charp)"DM dump_png()";
    text[0].compression = PNG_TEXT_COMPRESSION_NONE;
    text[1].key = (png_charp)"Description";
    text[1].text = (png_charp)description.c_str();
    text[1].compression = PNG_TEXT_COMPRESSION_NONE;
    png_set_text(png, info, text, 2);

    png_init_io(png, f);
    png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8,
                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    png_write_info(png, info);
    for (int j = 0; j < h; j++) {
        png_bytep row = (png_bytep)(rgba.get() + w*j);
        png_write_rows(png, &row, 1);
    }
    png_write_end(png, info);

    png_destroy_write_struct(&png, &info);
    fclose(f);
    return true;
}
Example #10
0
SkString GrDrawPathOp::dumpInfo() const {
    SkString string;
    string.printf("PATH: 0x%p", fPath.get());
    string.append(INHERITED::dumpInfo());
    return string;
}
int tool_main(int argc, char** argv) {
    DiffMetricProc diffProc = compute_diff_pmcolor;

    // Maximum error tolerated in any one color channel in any one pixel before
    // a difference is reported.
    int colorThreshold = 0;
    SkString baseFile;
    SkString baseLabel;
    SkString comparisonFile;
    SkString comparisonLabel;
    SkString outputDir;

    bool listFilenames = false;

    bool failOnResultType[DiffRecord::kResultCount];
    for (int i = 0; i < DiffRecord::kResultCount; i++) {
        failOnResultType[i] = false;
    }

    bool failOnStatusType[DiffResource::kStatusCount][DiffResource::kStatusCount];
    for (int base = 0; base < DiffResource::kStatusCount; ++base) {
        for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
            failOnStatusType[base][comparison] = false;
        }
    }

    int i;
    int numUnflaggedArguments = 0;
    int numLabelArguments = 0;
    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "--failonresult")) {
            if (argc == ++i) {
                SkDebugf("failonresult expects one argument.\n");
                continue;
            }
            DiffRecord::Result type = DiffRecord::getResultByName(argv[i]);
            if (type != DiffRecord::kResultCount) {
                failOnResultType[type] = true;
            } else {
                SkDebugf("ignoring unrecognized result <%s>\n", argv[i]);
            }
            continue;
        }
        if (!strcmp(argv[i], "--failonstatus")) {
            if (argc == ++i) {
                SkDebugf("failonstatus missing base status.\n");
                continue;
            }
            bool baseStatuses[DiffResource::kStatusCount];
            if (!DiffResource::getMatchingStatuses(argv[i], baseStatuses)) {
                SkDebugf("unrecognized base status <%s>\n", argv[i]);
            }

            if (argc == ++i) {
                SkDebugf("failonstatus missing comparison status.\n");
                continue;
            }
            bool comparisonStatuses[DiffResource::kStatusCount];
            if (!DiffResource::getMatchingStatuses(argv[i], comparisonStatuses)) {
                SkDebugf("unrecognized comarison status <%s>\n", argv[i]);
            }

            for (int base = 0; base < DiffResource::kStatusCount; ++base) {
                for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
                    failOnStatusType[base][comparison] |=
                        baseStatuses[base] && comparisonStatuses[comparison];
                }
            }
            continue;
        }
        if (!strcmp(argv[i], "--help")) {
            usage(argv[0]);
            return kNoError;
        }
        if (!strcmp(argv[i], "--listfilenames")) {
            listFilenames = true;
            continue;
        }
        if (!strcmp(argv[i], "--outputdir")) {
            if (argc == ++i) {
                SkDebugf("outputdir expects one argument.\n");
                continue;
            }
            outputDir.set(argv[i]);
            continue;
        }
        if (!strcmp(argv[i], "--threshold")) {
            colorThreshold = atoi(argv[++i]);
            continue;
        }
        if (!strcmp(argv[i], "-u")) {
            //we don't produce unified diffs, ignore parameter to work with svn diff
            continue;
        }
        if (!strcmp(argv[i], "-L")) {
            if (argc == ++i) {
                SkDebugf("label expects one argument.\n");
                continue;
            }
            switch (numLabelArguments++) {
                case 0:
                    baseLabel.set(argv[i]);
                    continue;
                case 1:
                    comparisonLabel.set(argv[i]);
                    continue;
                default:
                    SkDebugf("extra label argument <%s>\n", argv[i]);
                    usage(argv[0]);
                    return kGenericError;
            }
            continue;
        }
        if (argv[i][0] != '-') {
            switch (numUnflaggedArguments++) {
                case 0:
                    baseFile.set(argv[i]);
                    continue;
                case 1:
                    comparisonFile.set(argv[i]);
                    continue;
                default:
                    SkDebugf("extra unflagged argument <%s>\n", argv[i]);
                    usage(argv[0]);
                    return kGenericError;
            }
        }

        SkDebugf("Unrecognized argument <%s>\n", argv[i]);
        usage(argv[0]);
        return kGenericError;
    }

    if (numUnflaggedArguments != 2) {
        usage(argv[0]);
        return kGenericError;
    }

    if (listFilenames) {
        printf("Base file is [%s]\n", baseFile.c_str());
    }

    if (listFilenames) {
        printf("Comparison file is [%s]\n", comparisonFile.c_str());
    }

    if (outputDir.isEmpty()) {
        if (listFilenames) {
            printf("Not writing any diffs. No output dir specified.\n");
        }
    } else {
        if (!outputDir.endsWith(PATH_DIV_STR)) {
            outputDir.append(PATH_DIV_STR);
        }
        if (listFilenames) {
            printf("Writing diffs. Output dir is [%s]\n", outputDir.c_str());
        }
    }

    // Some obscure documentation about diff/patch labels:
    //
    // Posix says the format is: <filename><tab><date>
    //     It also states that if a filename contains <tab> or <newline>
    //     the result is implementation defined
    //
    // Svn diff --diff-cmd provides labels of the form: <filename><tab><revision>
    //
    // Git diff --ext-diff does not supply arguments compatible with diff.
    //     However, it does provide the filename directly.
    //     skimagediff_git.sh: skimagediff %2 %5 -L "%1\t(%3)" -L "%1\t(%6)"
    //
    // Git difftool sets $LOCAL, $REMOTE, $MERGED, and $BASE instead of command line parameters.
    //     difftool.<>.cmd: skimagediff $LOCAL $REMOTE -L "$MERGED\t(local)" -L "$MERGED\t(remote)"
    //
    // Diff will write any specified label verbatim. Without a specified label diff will write
    //     <filename><tab><date>
    //     However, diff will encode the filename as a cstring if the filename contains
    //         Any of <space> or <double quote>
    //         A char less than 32
    //         Any escapable character \\, \a, \b, \t, \n, \v, \f, \r
    //
    // Patch decodes:
    //     If first <non-white-space> is <double quote>, parse filename from cstring.
    //     If there is a <tab> after the first <non-white-space>, filename is
    //         [first <non-white-space>, the next run of <white-space> with an embedded <tab>).
    //     Otherwise the filename is [first <non-space>, the next <white-space>).
    //
    // The filename /dev/null means the file does not exist (used in adds and deletes).

    // Considering the above, skimagediff will consider the contents of a -L parameter as
    //     <filename>(\t<specifier>)?
    SkString outputFile;

    if (baseLabel.isEmpty()) {
        baseLabel.set(baseFile);
        outputFile = baseLabel;
    } else {
        const char* baseLabelCstr = baseLabel.c_str();
        const char* tab = strchr(baseLabelCstr, '\t');
        if (nullptr == tab) {
            outputFile = baseLabel;
        } else {
            outputFile.set(baseLabelCstr, tab - baseLabelCstr);
        }
    }
    if (comparisonLabel.isEmpty()) {
        comparisonLabel.set(comparisonFile);
    }
    printf("Base:       %s\n", baseLabel.c_str());
    printf("Comparison: %s\n", comparisonLabel.c_str());

    DiffRecord dr;
    create_diff_images(diffProc, colorThreshold, baseFile, comparisonFile, outputDir, outputFile,
                       &dr);

    if (DiffResource::isStatusFailed(dr.fBase.fStatus)) {
        printf("Base %s.\n", DiffResource::getStatusDescription(dr.fBase.fStatus));
    }
    if (DiffResource::isStatusFailed(dr.fComparison.fStatus)) {
        printf("Comparison %s.\n", DiffResource::getStatusDescription(dr.fComparison.fStatus));
    }
    printf("Base and Comparison %s.\n", DiffRecord::getResultDescription(dr.fResult));

    if (DiffRecord::kDifferentPixels_Result == dr.fResult) {
        printf("%.4f%% of pixels differ", 100 * dr.fFractionDifference);
        printf(" (%.4f%%  weighted)", 100 * dr.fWeightedFraction);
        if (dr.fFractionDifference < 0.01) {
            printf(" %d pixels", static_cast<int>(dr.fFractionDifference *
                                                  dr.fBase.fBitmap.width() *
                                                  dr.fBase.fBitmap.height()));
        }

        printf("\nAverage color mismatch: ");
        printf("%d", static_cast<int>(MAX3(dr.fAverageMismatchR,
                                           dr.fAverageMismatchG,
                                           dr.fAverageMismatchB)));
        printf("\nMax color mismatch: ");
        printf("%d", MAX3(dr.fMaxMismatchR,
                          dr.fMaxMismatchG,
                          dr.fMaxMismatchB));
        printf("\n");
    }
    printf("\n");

    int num_failing_results = 0;
    if (failOnResultType[dr.fResult]) {
        ++num_failing_results;
    }
    if (failOnStatusType[dr.fBase.fStatus][dr.fComparison.fStatus]) {
        ++num_failing_results;
    }

    return num_failing_results;
}
void SkSVGPaint::setSave(SkSVGParser& parser) {
    SkTDArray<SkString*> clips;
    SkSVGPaint* walking = parser.fHead;
    int index;
    SkMatrix sum;
    sum.reset();
    while (walking != NULL) {
        for (index = kInitial + 1; index < kTerminal; index++) {
            SkString* lastAttr = (*walking)[index];
            if (lastAttr->size() == 0)
                continue;
            if (index == kTransform) {
                const char* str = lastAttr->c_str();
                SkASSERT(strncmp(str, "matrix(", 7) == 0);
                str += 6;
                const char* strEnd = strrchr(str, ')');
                SkASSERT(strEnd != NULL);
                SkString mat(str, strEnd - str);
                SkSVGParser::ConvertToArray(mat);
                SkScalar values[6];
                SkParse::FindScalars(mat.c_str() + 1, values, 6);
                SkMatrix matrix;
                matrix.reset();
                matrix.setScaleX(values[0]);
                matrix.setSkewY(values[1]);
                matrix.setSkewX(values[2]);
                matrix.setScaleY(values[3]);
                matrix.setTranslateX(values[4]);
                matrix.setTranslateY(values[5]);
                sum.setConcat(matrix, sum);
                continue;
            }
            if ( index == kClipPath)
                *clips.insert(0) = lastAttr;
        }
        walking = walking->fNext;
    }
    if ((sum == parser.fLastTransform) == false) {
        SkMatrix inverse;
        bool success = parser.fLastTransform.invert(&inverse);
        SkASSERT(success == true);
        SkMatrix output;
        output.setConcat(inverse, sum);
        parser.fLastTransform = sum;
        SkString outputStr;
        outputStr.appendUnichar('[');
        outputStr.appendScalar(output.getScaleX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getSkewX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getTranslateX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getSkewY());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getScaleY());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getTranslateY());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getPerspX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getPerspY());
        outputStr.append(",1]");
        parser._startElement("matrix");
        parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size());
        parser._endElement();
    }
#if 0   // incomplete
    if (parser.fTransformClips.size() > 0) {
        // need to reset the clip when the 'g' scope is ended
        parser._startElement("add");
        const char* start = strchr(current->f_clipPath.c_str(), '#') + 1;
        SkASSERT(start);
        parser._addAttributeLen("use", start, strlen(start) - 1);
        parser._endElement();   // clip
    }
#endif
}
Example #13
0
void PictureBenchmark::run(SkPicture* pict) {
    SkASSERT(pict);
    if (NULL == pict) {
        return;
    }

    SkASSERT(fRenderer != NULL);
    if (NULL == fRenderer) {
        return;
    }

    fRenderer->init(pict, NULL, NULL, false);

    // We throw this away to remove first time effects (such as paging in this program)
    fRenderer->setup();

    if (fPreprocess) {
        if (NULL != fRenderer->getCanvas()) {
            fRenderer->getCanvas()->EXPERIMENTAL_optimize(pict);
        }
    }

    fRenderer->render(NULL);
    fRenderer->resetState(true);   // flush, swapBuffers and Finish

    if (fPreprocess) {
        if (NULL != fRenderer->getCanvas()) {
            fRenderer->getCanvas()->EXPERIMENTAL_purge(pict);
        }
    }

    if (fPurgeDecodedTex) {
        fRenderer->purgeTextures();
    }

    bool usingGpu = false;
#if SK_SUPPORT_GPU
    usingGpu = fRenderer->isUsingGpuDevice();
#endif

    uint32_t timerTypes = fTimerTypes;
    if (!usingGpu) {
        timerTypes &= ~TimerData::kGpu_Flag;
    }

    SkString timeFormat;
    if (TimerData::kPerIter_Result == fTimerResult) {
        timeFormat = fRenderer->getPerIterTimeFormat();
    } else {
        timeFormat = fRenderer->getNormalTimeFormat();
    }

    static const int kNumInnerLoops = 10;
    int numOuterLoops = 1;
    int numInnerLoops = fRepeats;

    if (TimerData::kPerIter_Result == fTimerResult && fRepeats > 1) {
        // interpret this flag combination to mean: generate 'fRepeats'
        // numbers by averaging each rendering 'kNumInnerLoops' times
        numOuterLoops = fRepeats;
        numInnerLoops = kNumInnerLoops;
    }

    if (fTimeIndividualTiles) {
        TiledPictureRenderer* tiledRenderer = fRenderer->getTiledRenderer();
        SkASSERT(tiledRenderer && tiledRenderer->supportsTimingIndividualTiles());
        if (NULL == tiledRenderer || !tiledRenderer->supportsTimingIndividualTiles()) {
            return;
        }
        int xTiles, yTiles;
        if (!tiledRenderer->tileDimensions(xTiles, yTiles)) {
            return;
        }

        // Insert a newline so that each tile is reported on its own line (separate from the line
        // that describes the skp being run).
        this->logProgress("\n");

        int x, y;
        while (tiledRenderer->nextTile(x, y)) {
            // There are two timers, which will behave slightly differently:
            // 1) longRunningTimer, along with perTileTimerData, will time how long it takes to draw
            // one tile fRepeats times, and take the average. As such, it will not respect the
            // logPerIter or printMin options, since it does not know the time per iteration. It
            // will also be unable to call flush() for each tile.
            // The goal of this timer is to make up for a system timer that is not precise enough to
            // measure the small amount of time it takes to draw one tile once.
            //
            // 2) perTileTimer, along with perTileTimerData, will record each run separately, and
            // then take the average. As such, it supports logPerIter and printMin options.
            //
            // Although "legal", having two gpu timers running at the same time
            // seems to cause problems (i.e., INVALID_OPERATIONs) on several
            // platforms. To work around this, we disable the gpu timer on the
            // long running timer.
            SkAutoTDelete<BenchTimer> longRunningTimer(this->setupTimer());
            TimerData longRunningTimerData(numOuterLoops);

            for (int outer = 0; outer < numOuterLoops; ++outer) {
                SkAutoTDelete<BenchTimer> perTileTimer(this->setupTimer(false));
                TimerData perTileTimerData(numInnerLoops);

                longRunningTimer->start();
                for (int inner = 0; inner < numInnerLoops; ++inner) {
                    perTileTimer->start();
                    tiledRenderer->drawCurrentTile();
                    perTileTimer->truncatedEnd();
                    tiledRenderer->resetState(false);  // flush & swapBuffers, but don't Finish
                    perTileTimer->end();
                    SkAssertResult(perTileTimerData.appendTimes(perTileTimer.get()));

                    if (fPurgeDecodedTex) {
                        fRenderer->purgeTextures();
                    }
                }
                longRunningTimer->truncatedEnd();
                tiledRenderer->resetState(true);       // flush, swapBuffers and Finish
                longRunningTimer->end();
                SkAssertResult(longRunningTimerData.appendTimes(longRunningTimer.get()));
            }

            SkString configName = tiledRenderer->getConfigName();
            configName.appendf(": tile [%i,%i] out of [%i,%i]", x, y, xTiles, yTiles);

            // TODO(borenet): Turn off per-iteration tile time reporting for now.
            // Avoiding logging the time for every iteration for each tile cuts
            // down on data file size by a significant amount. Re-enable this once
            // we're loading the bench data directly into a data store and are no
            // longer generating SVG graphs.
#if 0
            SkString result = perTileTimerData.getResult(timeFormat.c_str(), fTimerResult,
                                                         configName.c_str(), timerTypes);
            result.append("\n");
            this->logProgress(result.c_str());
#endif

            if (fPurgeDecodedTex) {
                configName.append(" <withPurging>");
            }
            configName.append(" <averaged>");
            SkString longRunningResult = longRunningTimerData.getResult(
                tiledRenderer->getNormalTimeFormat().c_str(),
                TimerData::kAvg_Result,
                configName.c_str(), timerTypes, numInnerLoops);
            longRunningResult.append("\n");
            this->logProgress(longRunningResult.c_str());
        }
    } else {
        SkAutoTDelete<BenchTimer> longRunningTimer(this->setupTimer());
        TimerData longRunningTimerData(numOuterLoops);

        for (int outer = 0; outer < numOuterLoops; ++outer) {
            SkAutoTDelete<BenchTimer> perRunTimer(this->setupTimer(false));
            TimerData perRunTimerData(numInnerLoops);

            longRunningTimer->start();
            for (int inner = 0; inner < numInnerLoops; ++inner) {
                fRenderer->setup();

                perRunTimer->start();
                fRenderer->render(NULL);
                perRunTimer->truncatedEnd();
                fRenderer->resetState(false);   // flush & swapBuffers, but don't Finish
                perRunTimer->end();

                SkAssertResult(perRunTimerData.appendTimes(perRunTimer.get()));

                if (fPreprocess) {
                    if (NULL != fRenderer->getCanvas()) {
                        fRenderer->getCanvas()->EXPERIMENTAL_purge(pict);
                    }
                }

                if (fPurgeDecodedTex) {
                    fRenderer->purgeTextures();
                }
            }
            longRunningTimer->truncatedEnd();
            fRenderer->resetState(true);        // flush, swapBuffers and Finish
            longRunningTimer->end();
            SkAssertResult(longRunningTimerData.appendTimes(longRunningTimer.get()));
        }

        SkString configName = fRenderer->getConfigName();
        if (fPurgeDecodedTex) {
            configName.append(" <withPurging>");
        }

        // Beware - since the per-run-timer doesn't ever include a glFinish it can
        // report a lower time then the long-running-timer
#if 0
        SkString result = perRunTimerData.getResult(timeFormat.c_str(),
                                                    fTimerResult,
                                                    configName.c_str(),
                                                    timerTypes);
        result.append("\n");

        this->logProgress(result.c_str());
#else
        SkString result = longRunningTimerData.getResult(timeFormat.c_str(),
                                                            fTimerResult,
                                                            configName.c_str(),
                                                            timerTypes,
                                                            numInnerLoops);
        result.append("\n");
        this->logProgress(result.c_str());
#endif
    }

    fRenderer->end();
}
Example #14
0
SearchState
SkFontSearchList::search( SkFontDownloadList * dlFonts )
{
    DIR * dp = NULL;
    struct dirent * d = NULL;

    ready();

    if( ( dp = opendir( SYSTEM_DL_FONTAPP_SRC_DIR ) ) == NULL )
    {
        HyLogef( "%s, opendir()", SYSTEM_DL_FONTAPP_SRC_DIR );
        goto ERROR0;
    }

    while( ( d = readdir( dp ) ) != NULL )
    {
        if( !strncmp( d->d_name, ".", 1 ) )
            continue;

        if( !strncmp( d->d_name, DL_FONTAPP_SEARCH_STR, DL_FONTAPP_SEARCH_LEN ) )
        {
            if( dlFonts->isExist( d->d_name ) == true )
                continue;
            else
            {
                SkFontData * font = SkNEW( SkFontData );

                if( font )
                {
                    SkString fontFullPath;
                    SkString fontDatPath;
                    SkString fontXmlPath;

                    font->setFontAppName( d->d_name );

                    fontFullPath.set( SYSTEM_DL_FONTAPP_DST_DIR );
                    fontFullPath.append( font->getFontAppName() );
                    fontFullPath.append( DLFILE_TTF );

                    fontDatPath.set( SYSTEM_DL_FONTAPP_DST_DIR );
                    fontDatPath.append( font->getFontAppName() );
                    fontDatPath.append( DLFILE_DAT );

                    fontXmlPath.set( SYSTEM_DL_FONTAPP_DST_DIR );
                    fontXmlPath.append( font->getFontAppName() );
                    fontXmlPath.append( DLFILE_XML );

                    font->setFontFullPath( fontFullPath.c_str() );
                    font->setFontDatPath( fontDatPath.c_str() );
                    font->setFontXmlPath( fontXmlPath.c_str() );
                    addFonts( font );
                }
                else
                {
                    HyLogef( "Error : SkNEW( SkFontData )." );
                    continue;
                }
            }
        }
    }

    closedir( dp );

    if( numFonts() > 0 )
        return setState( STATE_DL_FONTAPP_FIND );
    else
        return setState( STATE_DL_FONTAPP_KEEP );

ERROR0:
    setError( ERR_YES );
    return setState( STATE_DL_FONTAPP_KEEP );
}
Example #15
0
    static void WriteToDisk(const Task& task,
                            SkString md5,
                            const char* ext,
                            SkStream* data, size_t len,
                            const SkBitmap* bitmap) {
        JsonWriter::BitmapResult result;
        result.name          = task.src->name();
        result.config        = task.sink.tag;
        result.sourceType    = task.src.tag;
        result.sourceOptions = task.src.options;
        result.ext           = ext;
        result.md5           = md5;
        JsonWriter::AddBitmapResult(result);

        // If an MD5 is uninteresting, we want it noted in the JSON file,
        // but don't want to dump it out as a .png (or whatever ext is).
        if (gUninterestingHashes.contains(md5)) {
            return;
        }

        const char* dir = FLAGS_writePath[0];
        if (0 == strcmp(dir, "@")) {  // Needed for iOS.
            dir = FLAGS_resourcePath[0];
        }
        sk_mkdir(dir);

        SkString path;
        if (FLAGS_nameByHash) {
            path = SkOSPath::Join(dir, result.md5.c_str());
            path.append(".");
            path.append(ext);
            if (sk_exists(path.c_str())) {
                return;  // Content-addressed.  If it exists already, we're done.
            }
        } else {
            path = SkOSPath::Join(dir, task.sink.tag);
            sk_mkdir(path.c_str());
            path = SkOSPath::Join(path.c_str(), task.src.tag);
            sk_mkdir(path.c_str());
            if (strcmp(task.src.options, "") != 0) {
              path = SkOSPath::Join(path.c_str(), task.src.options);
              sk_mkdir(path.c_str());
            }
            path = SkOSPath::Join(path.c_str(), task.src->name().c_str());
            path.append(".");
            path.append(ext);
        }

        SkFILEWStream file(path.c_str());
        if (!file.isValid()) {
            fail(SkStringPrintf("Can't open %s for writing.\n", path.c_str()));
            return;
        }

        if (bitmap) {
            // We can't encode A8 bitmaps as PNGs.  Convert them to 8888 first.
            SkBitmap converted;
            if (bitmap->info().colorType() == kAlpha_8_SkColorType) {
                if (!bitmap->copyTo(&converted, kN32_SkColorType)) {
                    fail("Can't convert A8 to 8888.\n");
                    return;
                }
                bitmap = &converted;
            }
            if (!SkImageEncoder::EncodeStream(&file, *bitmap, SkImageEncoder::kPNG_Type, 100)) {
                fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str()));
                return;
            }
        } else {
            if (!file.writeStream(data, len)) {
                fail(SkStringPrintf("Can't write to %s.\n", path.c_str()));
                return;
            }
        }
    }
Example #16
0
    static void WriteToDisk(const Task& task,
                            SkString md5,
                            const char* ext,
                            SkStream* data, size_t len,
                            const SkBitmap* bitmap) {
        JsonWriter::BitmapResult result;
        result.name          = task.src->name();
        result.config        = task.sink.tag;
        result.sourceType    = task.src.tag;
        result.sourceOptions = task.src.options;
        result.ext           = ext;
        result.md5           = md5;
        JsonWriter::AddBitmapResult(result);

        // If an MD5 is uninteresting, we want it noted in the JSON file,
        // but don't want to dump it out as a .png (or whatever ext is).
        if (gUninterestingHashes.contains(md5)) {
            return;
        }

        const char* dir = FLAGS_writePath[0];
        if (0 == strcmp(dir, "@")) {  // Needed for iOS.
            dir = FLAGS_resourcePath[0];
        }
        sk_mkdir(dir);

        SkString path;
        if (FLAGS_nameByHash) {
            path = SkOSPath::Join(dir, result.md5.c_str());
            path.append(".");
            path.append(ext);
            if (sk_exists(path.c_str())) {
                return;  // Content-addressed.  If it exists already, we're done.
            }
        } else {
            path = SkOSPath::Join(dir, task.sink.tag);
            sk_mkdir(path.c_str());
            path = SkOSPath::Join(path.c_str(), task.src.tag.c_str());
            sk_mkdir(path.c_str());
            if (strcmp(task.src.options.c_str(), "") != 0) {
              path = SkOSPath::Join(path.c_str(), task.src.options.c_str());
              sk_mkdir(path.c_str());
            }
            path = SkOSPath::Join(path.c_str(), task.src->name().c_str());
            path.append(".");
            path.append(ext);
        }

        if (bitmap) {
            if (!dump_png(*bitmap, path.c_str(), result.md5.c_str())) {
                fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str()));
                return;
            }
        } else {
            SkFILEWStream file(path.c_str());
            if (!file.isValid()) {
                fail(SkStringPrintf("Can't open %s for writing.\n", path.c_str()));
                return;
            }
            if (!file.writeStream(data, len)) {
                fail(SkStringPrintf("Can't write to %s.\n", path.c_str()));
                return;
            }
        }
    }
static void TestString(skiatest::Reporter* reporter) {
    SkString    a;
    SkString    b((size_t)0);
    SkString    c("");
    SkString    d(NULL, 0);

    REPORTER_ASSERT(reporter, a.isEmpty());
    REPORTER_ASSERT(reporter, a == b && a == c && a == d);

    a.set("hello");
    b.set("hellox", 5);
    c.set(a);
    d.resize(5);
    memcpy(d.writable_str(), "helloz", 5);

    REPORTER_ASSERT(reporter, !a.isEmpty());
    REPORTER_ASSERT(reporter, a.size() == 5);
    REPORTER_ASSERT(reporter, a == b && a == c && a == d);
    REPORTER_ASSERT(reporter, a.equals("hello", 5));
    REPORTER_ASSERT(reporter, a.equals("hello"));
    REPORTER_ASSERT(reporter, !a.equals("help"));

    SkString    e(a);
    SkString    f("hello");
    SkString    g("helloz", 5);

    REPORTER_ASSERT(reporter, a == e && a == f && a == g);

    b.set("world");
    c = b;
    REPORTER_ASSERT(reporter, a != b && a != c && b == c);

    a.append(" world");
    e.append("worldz", 5);
    e.insert(5, " ");
    f.set("world");
    f.prepend("hello ");
    REPORTER_ASSERT(reporter, a.equals("hello world") && a == e && a == f);

    a.reset();
    b.resize(0);
    REPORTER_ASSERT(reporter, a.isEmpty() && b.isEmpty() && a == b);

    a.set("a");
    a.set("ab");
    a.set("abc");
    a.set("abcd");

    a.set("");
    a.appendS64(72036854775808LL, 0);
    REPORTER_ASSERT(reporter, a.equals("72036854775808"));

    a.set("");
    a.appendS64(-1844674407370LL, 0);
    REPORTER_ASSERT(reporter, a.equals("-1844674407370"));

    a.set("");
    a.appendS64(73709551616LL, 15);
    REPORTER_ASSERT(reporter, a.equals("000073709551616"));

    a.set("");
    a.appendS64(-429496729612LL, 15);
    REPORTER_ASSERT(reporter, a.equals("-000429496729612"));

    static const struct {
        SkScalar    fValue;
        const char* fString;
    } gRec[] = {
        { 0,            "0" },
        { SK_Scalar1,   "1" },
        { -SK_Scalar1,  "-1" },
        { SK_Scalar1/2, "0.5" },
#ifdef SK_SCALAR_IS_FLOAT
  #ifdef SK_BUILD_FOR_WIN
        { 3.4028234e38f,   "3.4028235e+038" },
        { -3.4028234e38f, "-3.4028235e+038" },
  #else
        { 3.4028234e38f,   "3.4028235e+38" },
        { -3.4028234e38f, "-3.4028235e+38" },
  #endif
#endif
    };
    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
        a.reset();
        a.appendScalar(gRec[i].fValue);
        REPORTER_ASSERT(reporter, a.size() <= SkStrAppendScalar_MaxSize);
//        SkDebugf(" received <%s> expected <%s>\n", a.c_str(), gRec[i].fString);
        REPORTER_ASSERT(reporter, a.equals(gRec[i].fString));
    }

    REPORTER_ASSERT(reporter, SkStringPrintf("%i", 0).equals("0"));

    char buffer [40];
    memset(buffer, 'a', 40);
    REPORTER_ASSERT(reporter, buffer[18] == 'a');
    REPORTER_ASSERT(reporter, buffer[19] == 'a');
    REPORTER_ASSERT(reporter, buffer[20] == 'a');
    printfAnalog(buffer, 20, "%30d", 0);
    REPORTER_ASSERT(reporter, buffer[18] == ' ');
    REPORTER_ASSERT(reporter, buffer[19] == 0);
    REPORTER_ASSERT(reporter, buffer[20] == 'a');
    
}
bool SkAnimator::onEvent(const SkEvent& evt) {
#ifdef SK_DEBUG
    SkAnimator* root = fMaker->getRoot();
    if (root == NULL)
        root = this;
    if (root->isTrackingEvents())
        root->eventDone(evt);
#endif
    if (evt.isType(SK_EventType_OnEnd)) {
        SkEventState eventState;
        bool success = evt.findPtr("anim", (void**) &eventState.fDisplayable);
        SkASSERT(success);
        success = evt.findS32("time", (int32_t*) &fMaker->fEnableTime);
        SkASSERT(success);
        fMaker->fAdjustedStart = fMaker->getAppTime() - fMaker->fEnableTime;
        fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kOnEnd, &eventState);
        fMaker->fAdjustedStart = 0;
        goto inval;
    }
    if (evt.isType(SK_EventType_Delay)) {
        fMaker->doDelayedEvent();
        goto inval;
    }
    {
        const char* id = evt.findString("id");
        if (id == NULL)
            return false;
        SkDisplayable** firstMovie = fMaker->fMovies.begin();
        SkDisplayable** endMovie = fMaker->fMovies.end();
        for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
            SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
            movie->doEvent(evt);
        }
        {
            SkDisplayable* event;
            if (fMaker->find(id, &event) == false)
                return false;
    #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
            SkString debugOut;
            SkMSec realTime = fMaker->getAppTime();
            debugOut.appendS32(realTime - fMaker->fDebugTimeBase);
            debugOut.append(" onEvent id=");
            debugOut.append(id);
    #endif
            SkMSec time = evt.getFast32();
            if (time != 0) {
                SkMSec app  = fMaker->getAppTime();
                fMaker->setEnableTime(app, time);
    #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
                debugOut.append(" time=");
                debugOut.appendS32(time - fMaker->fDebugTimeBase);
                debugOut.append(" adjust=");
                debugOut.appendS32(fMaker->fAdjustedStart);
    #endif
            }
    #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
            SkDebugf("%s\n", debugOut.c_str());
    #endif
            SkASSERT(event->isEvent());
            SkDisplayEvent* displayEvent = (SkDisplayEvent*) event;
            displayEvent->populateInput(*fMaker, evt);
            displayEvent->enableEvent(*fMaker);
        }
    }
inval:
    fMaker->notifyInval();
    return true;
}
Example #19
0
SkString* SkObjectParser::BitmapToString(const SkBitmap& bitmap) {
    SkString* mBitmap = new SkString("SkBitmap: ");
    mBitmap->append("W: ");
    mBitmap->appendS32(bitmap.width());
    mBitmap->append(" H: ");
    mBitmap->appendS32(bitmap.height());

    const char* gConfigStrings[] = {
        "None", "A1", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
    };
    SkASSERT(SkBitmap::kConfigCount == 7);

    mBitmap->append(" Config: ");
    mBitmap->append(gConfigStrings[bitmap.config()]);

    if (bitmap.isOpaque()) {
        mBitmap->append(" opaque");
    } else {
        mBitmap->append(" not-opaque");
    }

    if (bitmap.isImmutable()) {
        mBitmap->append(" immutable");
    } else {
        mBitmap->append(" not-immutable");
    }

    if (bitmap.isVolatile()) {
        mBitmap->append(" volatile");
    } else {
        mBitmap->append(" not-volatile");
    }

    mBitmap->append(" genID: ");
    mBitmap->appendS32(bitmap.getGenerationID());

    return mBitmap;
}
Example #20
0
bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
                                                    VkShaderStageFlagBits stage,
                                                    const GrGLSLShaderBuilder& builder,
                                                    VkShaderModule* shaderModule,
                                                    VkPipelineShaderStageCreateInfo* stageInfo) {
    SkString shaderString;
    for (int i = 0; i < builder.fCompilerStrings.count(); ++i) {
        if (builder.fCompilerStrings[i]) {
            shaderString.append(builder.fCompilerStrings[i]);
            shaderString.append("\n");
        }
    }

    VkShaderModuleCreateInfo moduleCreateInfo;
    memset(&moduleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo));
    moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
    moduleCreateInfo.pNext = nullptr;
    moduleCreateInfo.flags = 0;

#if USE_SKSL
    std::string code;
#else
    shaderc_compilation_result_t result = nullptr;
#endif

    if (gpu->vkCaps().canUseGLSLForShaderModule()) {
        moduleCreateInfo.codeSize = strlen(shaderString.c_str());
        moduleCreateInfo.pCode = (const uint32_t*)shaderString.c_str();
    } else {

#if USE_SKSL
        bool result = gpu->shaderCompiler()->toSPIRV(vk_shader_stage_to_skiasl_kind(stage), 
                                                     std::string(shaderString.c_str()),
                                                     &code);
        if (!result) {
            SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
            return false;
        }
        moduleCreateInfo.codeSize = code.size();
        moduleCreateInfo.pCode = (const uint32_t*) code.c_str();
#else
        shaderc_compiler_t compiler = gpu->shadercCompiler();

        shaderc_compile_options_t options = shaderc_compile_options_initialize();

        shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage);
        result = shaderc_compile_into_spv(compiler,
                                          shaderString.c_str(),
                                          strlen(shaderString.c_str()),
                                          shadercStage,
                                          "shader",
                                          "main",
                                          options);
        shaderc_compile_options_release(options);
#ifdef SK_DEBUG
        if (shaderc_result_get_num_errors(result)) {
            SkDebugf("%s\n", shaderString.c_str());
            SkDebugf("%s\n", shaderc_result_get_error_message(result));
            return false;
        }
#endif // SK_DEBUG

        moduleCreateInfo.codeSize = shaderc_result_get_length(result);
        moduleCreateInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result);
#endif // USE_SKSL
    }

    VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(),
                                                                     &moduleCreateInfo,
                                                                     nullptr,
                                                                     shaderModule));

    if (!gpu->vkCaps().canUseGLSLForShaderModule()) {
#if !USE_SKSL
        shaderc_result_release(result);
#endif
    }
    if (err) {
        return false;
    }

    memset(stageInfo, 0, sizeof(VkPipelineShaderStageCreateInfo));
    stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    stageInfo->pNext = nullptr;
    stageInfo->flags = 0;
    stageInfo->stage = stage;
    stageInfo->module = *shaderModule;
    stageInfo->pName = "main";
    stageInfo->pSpecializationInfo = nullptr;

    return true;
}
Example #21
0
SkString* SkObjectParser::IntToString(int x, const char* text) {
    SkString* mInt = new SkString(text);
    mInt->append(" ");
    mInt->appendScalar(SkIntToScalar(x));
    return mInt;
}
void GrGLPerlinNoise::emitCode(EmitArgs& args) {
    const GrPerlinNoiseEffect& pne = args.fFp.cast<GrPerlinNoiseEffect>();

    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    SkString vCoords = fragBuilder->ensureFSCoords2D(args.fCoords, 0);

    fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                   kVec2f_GrSLType, kDefault_GrSLPrecision,
                                                   "baseFrequency");
    const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);

    const char* stitchDataUni = nullptr;
    if (pne.stitchTiles()) {
        fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                    kVec2f_GrSLType, kDefault_GrSLPrecision,
                                                    "stitchData");
        stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
    }

    // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
    const char* chanCoordR  = "0.125";
    const char* chanCoordG  = "0.375";
    const char* chanCoordB  = "0.625";
    const char* chanCoordA  = "0.875";
    const char* chanCoord   = "chanCoord";
    const char* stitchData  = "stitchData";
    const char* ratio       = "ratio";
    const char* noiseVec    = "noiseVec";
    const char* noiseSmooth = "noiseSmooth";
    const char* floorVal    = "floorVal";
    const char* fractVal    = "fractVal";
    const char* uv          = "uv";
    const char* ab          = "ab";
    const char* latticeIdx  = "latticeIdx";
    const char* bcoords     = "bcoords";
    const char* lattice     = "lattice";
    const char* inc8bit     = "0.00390625";  // 1.0 / 256.0
    // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
    // [-1,1] vector and perform a dot product between that vector and the provided vector.
    const char* dotLattice  = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);";

    // Add noise function
    static const GrGLSLShaderVar gPerlinNoiseArgs[] =  {
        GrGLSLShaderVar(chanCoord, kFloat_GrSLType),
        GrGLSLShaderVar(noiseVec, kVec2f_GrSLType)
    };

    static const GrGLSLShaderVar gPerlinNoiseStitchArgs[] =  {
        GrGLSLShaderVar(chanCoord, kFloat_GrSLType),
        GrGLSLShaderVar(noiseVec, kVec2f_GrSLType),
        GrGLSLShaderVar(stitchData, kVec2f_GrSLType)
    };

    SkString noiseCode;

    noiseCode.appendf("\tvec4 %s;\n", floorVal);
    noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
    noiseCode.appendf("\t%s.zw = %s.xy + vec2(1.0);\n", floorVal, floorVal);
    noiseCode.appendf("\tvec2 %s = fract(%s);\n", fractVal, noiseVec);

    // smooth curve : t * t * (3 - 2 * t)
    noiseCode.appendf("\n\tvec2 %s = %s * %s * (vec2(3.0) - vec2(2.0) * %s);",
        noiseSmooth, fractVal, fractVal, fractVal);

    // Adjust frequencies if we're stitching tiles
    if (pne.stitchTiles()) {
        noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
                          floorVal, stitchData, floorVal, stitchData);
        noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
                          floorVal, stitchData, floorVal, stitchData);
        noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
                          floorVal, stitchData, floorVal, stitchData);
        noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
                          floorVal, stitchData, floorVal, stitchData);
    }

    // Get texture coordinates and normalize
    noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / vec4(256.0));\n",
                      floorVal, floorVal);

    // Get permutation for x
    {
        SkString xCoords("");
        xCoords.appendf("vec2(%s.x, 0.5)", floorVal);

        noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
        fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
                                         kVec2f_GrSLType);
        noiseCode.append(".r;");
    }

    // Get permutation for x + 1
    {
        SkString xCoords("");
        xCoords.appendf("vec2(%s.z, 0.5)", floorVal);

        noiseCode.appendf("\n\t%s.y = ", latticeIdx);
        fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
                                         kVec2f_GrSLType);
        noiseCode.append(".r;");
    }

#if defined(SK_BUILD_FOR_ANDROID)
    // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
    // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
    // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
    // (or 0.484368 here). The following rounding operation prevents these precision issues from
    // affecting the result of the noise by making sure that we only have multiples of 1/255.
    // (Note that 1/255 is about 0.003921569, which is the value used here).
    noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);",
                      latticeIdx, latticeIdx);
#endif

    // Get (x,y) coordinates with the permutated x
    noiseCode.appendf("\n\tvec4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);

    noiseCode.appendf("\n\n\tvec2 %s;", uv);
    // Compute u, at offset (0,0)
    {
        SkString latticeCoords("");
        latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord);
        noiseCode.appendf("\n\tvec4 %s = ", lattice);
        fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
                                         kVec2f_GrSLType);
        noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
    }

    noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
    // Compute v, at offset (-1,0)
    {
        SkString latticeCoords("");
        latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord);
        noiseCode.append("\n\tlattice = ");
        fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
                                         kVec2f_GrSLType);
        noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
    }

    // Compute 'a' as a linear interpolation of 'u' and 'v'
    noiseCode.appendf("\n\tvec2 %s;", ab);
    noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);

    noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
    // Compute v, at offset (-1,-1)
    {
        SkString latticeCoords("");
        latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord);
        noiseCode.append("\n\tlattice = ");
        fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
                                         kVec2f_GrSLType);
        noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
    }

    noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
    // Compute u, at offset (0,-1)
    {
        SkString latticeCoords("");
        latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord);
        noiseCode.append("\n\tlattice = ");
        fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
                                         kVec2f_GrSLType);
        noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
        noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
    }

    // Compute 'b' as a linear interpolation of 'u' and 'v'
    noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
    // Compute the noise as a linear interpolation of 'a' and 'b'
    noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);

    SkString noiseFuncName;
    if (pne.stitchTiles()) {
        fragBuilder->emitFunction(kFloat_GrSLType,
                                  "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
                                  gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
    } else {
        fragBuilder->emitFunction(kFloat_GrSLType,
                                  "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
                                  gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
    }

    // There are rounding errors if the floor operation is not performed here
    fragBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
                             noiseVec, vCoords.c_str(), baseFrequencyUni);

    // Clear the color accumulator
    fragBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", args.fOutputColor);

    if (pne.stitchTiles()) {
        // Set up TurbulenceInitial stitch values.
        fragBuilder->codeAppendf("vec2 %s = %s;", stitchData, stitchDataUni);
    }

    fragBuilder->codeAppendf("float %s = 1.0;", ratio);

    // Loop over all octaves
    fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());

    fragBuilder->codeAppendf("%s += ", args.fOutputColor);
    if (pne.type() != SkPerlinNoiseShader::kFractalNoise_Type) {
        fragBuilder->codeAppend("abs(");
    }
    if (pne.stitchTiles()) {
        fragBuilder->codeAppendf(
            "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
                 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
            noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
            noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
            noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
            noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
    } else {
        fragBuilder->codeAppendf(
            "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
                 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
            noiseFuncName.c_str(), chanCoordR, noiseVec,
            noiseFuncName.c_str(), chanCoordG, noiseVec,
            noiseFuncName.c_str(), chanCoordB, noiseVec,
            noiseFuncName.c_str(), chanCoordA, noiseVec);
    }
    if (pne.type() != SkPerlinNoiseShader::kFractalNoise_Type) {
        fragBuilder->codeAppendf(")"); // end of "abs("
    }
    fragBuilder->codeAppendf(" * %s;", ratio);

    fragBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
    fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);

    if (pne.stitchTiles()) {
        fragBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
    }
    fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves

    if (pne.type() == SkPerlinNoiseShader::kFractalNoise_Type) {
        // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
        // by fractalNoise and (turbulenceFunctionResult) by turbulence.
        fragBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);",
                                 args.fOutputColor,args.fOutputColor);
    }

    // Clamp values
    fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);

    // Pre-multiply the result
    fragBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
                             args.fOutputColor, args.fOutputColor,
                             args.fOutputColor, args.fOutputColor);
}
Example #23
0
static SkString make_png_name(const char* filename) {
    SkString pngName = SkString(filename);
    pngName.remove(pngName.size() - 3, 3);
    pngName.append("png");
    return pngName;
}
Example #24
0
bool SkApply::enable(SkAnimateMaker& maker) {
    fEnabled = true;
    bool initialized = fActive != NULL;
    if (dynamicScope.size() > 0)
        enableDynamic(maker);
    if (maker.fError.hasError()) 
        return false;
    int animators = fAnimators.count();
    int index;
    for (index = 0; index < animators; index++) {
        SkAnimateBase* animator = fAnimators[index];
        animator->fStart = maker.fEnableTime;
        animator->fResetPending = animator->fReset;
    }
    if (scope && scope->isApply())
        ((SkApply*) scope)->setEmbedded();
/*  if (mode == kMode_once) {
        if (scope) {
            activate(maker);
            interpolate(maker, maker.fEnableTime);
            inactivate(maker);
        }
        return true;
    }*/
    if ((mode == kMode_immediate || mode == kMode_create) && scope == NULL)
        return false;   // !!! error?
    bool enableMe = scope && (scope->hasEnable() || scope->isApply() || scope->isDrawable() == false);
    if (mode == kMode_immediate && enableMe || mode == kMode_create)
        activate(maker);    // for non-drawables like post, prime them here
    if (mode == kMode_immediate && enableMe)
        fActive->enable();
    if (mode == kMode_create && scope != NULL) {
        enableCreate(maker);
        return true;
    }
    if (mode == kMode_immediate) {
        return scope->isApply() || scope->isDrawable() == false;
    }
    refresh(maker);
    SkDisplayList& displayList = maker.fDisplayList;
    SkDrawable* drawable;
#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
    SkString debugOut;
    SkMSec time = maker.getAppTime();
    debugOut.appendS32(time - maker.fDebugTimeBase);
    debugOut.append(" apply enable id=");
    debugOut.append(_id);
    debugOut.append("; start=");
    debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase);
    SkDebugf("%s\n", debugOut.c_str());
#endif
    if (scope == NULL || scope->isApply() || scope->getType() == SkType_Movie || scope->isDrawable() == false) {
        activate(maker);    // for non-drawables like post, prime them here
        if (initialized) {
            append(this);
        }
        fEnabling = true;
        interpolate(maker, maker.fEnableTime);
        fEnabling = false;
        if (scope != NULL && dontDraw == false)
            scope->enable(maker);
        return true;
    } else if (initialized && restore == false)
        append(this);
#if 0
    bool wasActive = inactivate(maker); // start fresh
    if (wasActive) {
        activate(maker);
        interpolate(maker, maker.fEnableTime);
        return true;
    }
#endif
//  start here;
    // now that one apply might embed another, only the parent apply should replace the scope 
    // or get appended to the display list
    // similarly, an apply added by an add immediate has already been located in the display list
    // and should not get moved or added again here
    if (fEmbedded) {
        return false;   // already added to display list by embedder
    }
    drawable = (SkDrawable*) scope;
    SkTDDrawableArray* parentList;
    SkTDDrawableArray* grandList;
    SkGroup* parentGroup;
    SkGroup* thisGroup;
    int old = displayList.findGroup(drawable, &parentList, &parentGroup, &thisGroup, &grandList);
    if (old < 0)
        goto append;
    else if (fContainsScope) {
        if ((*parentList)[old] != this || restore == true) {
append:
            if (parentGroup)
                parentGroup->markCopySize(old);
            if (parentList->count() < 10000) {
                fAppended = true;
                *parentList->append() = this;
            } else
                maker.setErrorCode(SkDisplayXMLParserError::kDisplayTreeTooDeep);
            old = -1;
        } else
            reset();
    } else {
        SkASSERT(old < parentList->count());
        if ((*parentList)[old]->isApply()) {
            SkApply* apply = (SkApply*) (*parentList)[old];
            if (apply != this && apply->fActive == NULL)
                apply->activate(maker);
            apply->append(this);
            parentGroup = NULL;
        } else {
            if (parentGroup)
                parentGroup->markCopySize(old);
            SkDrawable** newApplyLocation = &(*parentList)[old];
            SkGroup* pGroup;
            int oldApply = displayList.findGroup(this, &parentList, &pGroup, &thisGroup, &grandList);
            if (oldApply >= 0) {
                (*parentList)[oldApply] = (SkDrawable*) SkDisplayType::CreateInstance(&maker, SkType_Apply);
                parentGroup = NULL;
                fDeleteScope = true;
            }
            *newApplyLocation = this;
        }
    }
    if (parentGroup) {
        parentGroup->markCopySet(old);
        fDeleteScope = dynamicScope.size() == 0;
    }
    return true;
}
Example #25
0
/**
 * Write the canvas to an image file and/or JSON summary.
 *
 * @param canvas Must be non-null. Canvas to be written to a file.
 * @param writePath If nonempty, write the binary image to a file within this directory.
 * @param mismatchPath If nonempty, write the binary image to a file within this directory,
 *     but only if the image does not match expectations.
 * @param inputFilename If we are writing out a binary image, use this to build its filename.
 * @param jsonSummaryPtr If not null, add image results (checksum) to this summary.
 * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
 * @param tileNumberPtr If not null, which tile number this image contains.
 *
 * @return bool True if the operation completed successfully.
 */
static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath,
                  const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr,
                  bool useChecksumBasedFilenames, const int* tileNumberPtr=NULL) {
    SkASSERT(canvas != NULL);
    if (NULL == canvas) {
        return false;
    }

    SkBitmap bitmap;
    SkISize size = canvas->getDeviceSize();
    setup_bitmap(&bitmap, size.width(), size.height());

    canvas->readPixels(&bitmap, 0, 0);
    force_all_opaque(bitmap);
    BitmapAndDigest bitmapAndDigest(bitmap);

    SkString escapedInputFilename(inputFilename);
    replace_char(&escapedInputFilename, '.', '_');

    // TODO(epoger): what about including the config type within outputFilename?  That way,
    // we could combine results of different config types without conflicting filenames.
    SkString outputFilename;
    const char *outputSubdirPtr = NULL;
    if (useChecksumBasedFilenames) {
        const ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
        outputSubdirPtr = escapedInputFilename.c_str();
        outputFilename.set(imageDigestPtr->getHashType());
        outputFilename.append("_");
        outputFilename.appendU64(imageDigestPtr->getHashValue());
    } else {
        outputFilename.set(escapedInputFilename);
        if (NULL != tileNumberPtr) {
            outputFilename.append("-tile");
            outputFilename.appendS32(*tileNumberPtr);
        }
    }
    outputFilename.append(".png");

    if (NULL != jsonSummaryPtr) {
        const ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
        SkString outputRelativePath;
        if (outputSubdirPtr) {
            outputRelativePath.set(outputSubdirPtr);
            outputRelativePath.append("/");  // always use "/", even on Windows
            outputRelativePath.append(outputFilename);
        } else {
            outputRelativePath.set(outputFilename);
        }

        jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(),
                            *imageDigestPtr, tileNumberPtr);
        if (!mismatchPath.isEmpty() &&
            !jsonSummaryPtr->matchesExpectation(inputFilename.c_str(), *imageDigestPtr,
                                                tileNumberPtr)) {
            if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) {
                return false;
            }
        }
    }

    if (writePath.isEmpty()) {
        return true;
    } else {
        return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename);
    }
}
Example #26
0
bool SkApply::interpolate(SkAnimateMaker& maker, SkMSec rawTime) {
    if (fActive == NULL)
        return false;
    bool result = false;
#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
    SkMSec time = maker.getAppTime();
    if (lastTime == (SkMSec) -1)
        lastTime = rawTime - 1;
    if (fActive != NULL && 
        strcmp(id, "a3") == 0 && rawTime > lastTime) {
        lastTime += 1000;
        SkString debugOut;
        debugOut.appendS32(time - maker.fDebugTimeBase);
        debugOut.append(" apply id=");
        debugOut.append(_id);
        debugOut.append("; ");
        debugOut.append(fActive->fAnimators[0]->_id);
        debugOut.append("=");
        debugOut.appendS32(rawTime - fActive->fState[0].fStartTime);
        debugOut.append(")");
        SkDebugf("%s\n", debugOut.c_str());
    }
#endif
    fActive->start();
    if (restore)
        fActive->initializeSave();
    int animators = fActive->fAnimators.count();
    for (int inner = 0; inner < animators; inner++) {
        SkAnimateBase* animate = fActive->fAnimators[inner];
        if (animate->fChanged) {
            animate->fChanged = false;
            animate->fStart = rawTime;
    //      SkTypedArray values;
    //      int count = animate->fValues.count();
    //      values.setCount(count);
    //      memcpy(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count);
            animate->onEndElement(maker);
    //      if (memcmp(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count) != 0) {
                fActive->append(this);
                fActive->start();
    //      }
        }
        SkMSec time = fActive->getTime(rawTime, inner);
        SkActive::SkState& state = fActive->fState[inner];
        if (SkMSec_LT(rawTime, state.fStartTime)) {
            if (fEnabling) {
                animate->fDelayed = true;
                maker.delayEnable(this, state.fStartTime);
            }
            continue;
        } else
            animate->fDelayed = false;
        SkMSec innerTime = fLastTime = state.getRelativeTime(time);
        if (restore) 
            fActive->restoreInterpolatorValues(inner);
        if (animate->fReset) {
            if (transition != SkApply::kTransition_reverse) {
                if (SkMSec_LT(state.fBegin + state.fDuration, innerTime)) {
                    if (animate->fResetPending) {
                        innerTime = 0;
                        animate->fResetPending = false;
                    } else
                        continue;
                }
            } else if (innerTime == 0) {
                    if (animate->fResetPending) {
                        innerTime = state.fBegin + state.fDuration;
                        animate->fResetPending = false;
                    } else
                        continue;
            }
        }
        int count = animate->components();
        SkAutoSTMalloc<16, SkOperand> values(count);
        SkInterpolatorBase::Result interpResult = fActive->fInterpolators[inner]->timeToValues(
            innerTime, values.get());
        result |= (interpResult != SkInterpolatorBase::kFreezeEnd_Result);
        if ((transition != SkApply::kTransition_reverse && interpResult == SkInterpolatorBase::kFreezeEnd_Result ||
                transition == SkApply::kTransition_reverse && fLastTime == 0) && state.fUnpostedEndEvent) {
//          SkDEBUGF(("interpolate: post on end\n"));
            state.fUnpostedEndEvent = false;
            maker.postOnEnd(animate, state.fBegin + state.fDuration);
            maker.fAdjustedStart = 0;    // !!! left over from synchronizing animation days, undoubtably out of date (and broken)
        }
        if (animate->formula.size() > 0) {
            if (fLastTime > animate->dur)
                fLastTime = animate->dur;
            SkTypedArray formulaValues;
            formulaValues.setCount(count);
            bool success = animate->fFieldInfo->setValue(maker, &formulaValues, 0, 0, NULL, 
                animate->getValuesType(), animate->formula);
            SkASSERT(success);
            if (restore)
                save(inner); // save existing value
            applyValues(inner, formulaValues.begin(), count, animate->getValuesType(), innerTime);
        } else {
            if (restore)
                save(inner); // save existing value
            applyValues(inner, values.get(), count, animate->getValuesType(), innerTime);
        }
    }
    return result;
}
Example #27
0
SkString* SkObjectParser::PathToString(const SkPath& path) {
    SkString* mPath = new SkString;

    mPath->appendf("Path (%d) (", path.getGenerationID());

    static const char* gFillStrings[] = {
        "Winding", "EvenOdd", "InverseWinding", "InverseEvenOdd"
    };

    mPath->append(gFillStrings[path.getFillType()]);
    mPath->append(", ");

    static const char* gConvexityStrings[] = {
        "Unknown", "Convex", "Concave"
    };
    SkASSERT(SkPath::kConcave_Convexity == 2);

    mPath->append(gConvexityStrings[path.getConvexity()]);
    mPath->append(", ");

    if (path.isRect(nullptr)) {
        mPath->append("isRect, ");
    } else {
        mPath->append("isNotRect, ");
    }

    if (path.isOval(nullptr)) {
        mPath->append("isOval, ");
    } else {
        mPath->append("isNotOval, ");
    }

    SkRRect rrect;
    if (path.isRRect(&rrect)) {
        mPath->append("isRRect, ");
    } else {
        mPath->append("isNotRRect, ");
    }

    mPath->appendS32(path.countVerbs());
    mPath->append("V, ");
    mPath->appendS32(path.countPoints());
    mPath->append("P): ");

    static const char* gVerbStrings[] = {
        "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done"
    };
    static const int gPtsPerVerb[] = { 1, 1, 2, 2, 3, 0, 0 };
    static const int gPtOffsetPerVerb[] = { 0, 1, 1, 1, 1, 0, 0 };
    SkASSERT(SkPath::kDone_Verb == 6);

    SkPath::Iter iter(const_cast<SkPath&>(path), false);
    SkPath::Verb verb;
    SkPoint points[4];

    for(verb = iter.next(points, false);
        verb != SkPath::kDone_Verb;
        verb = iter.next(points, false)) {

        mPath->append(gVerbStrings[verb]);
        mPath->append(" ");

        for (int i = 0; i < gPtsPerVerb[verb]; ++i) {
            mPath->append("(");
            mPath->appendScalar(points[gPtOffsetPerVerb[verb]+i].fX);
            mPath->append(", ");
            mPath->appendScalar(points[gPtOffsetPerVerb[verb]+i].fY);
            mPath->append(")");
        }

        if (SkPath::kConic_Verb == verb) {
            mPath->append("(");
            mPath->appendScalar(iter.conicWeight());
            mPath->append(")");
        }

        mPath->append(" ");
    }

    SkString* boundStr = SkObjectParser::RectToString(path.getBounds(), "    Bound: ");

    if (boundStr) {
        mPath->append(*boundStr);
        delete boundStr;
    }

    return mPath;
}
Example #28
0
int tool_main(int argc, char** argv) {
    DiffMetricProc diffProc = compute_diff_pmcolor;
    int (*sortProc)(const void*, const void*) = compare<CompareDiffMetrics>;

    // Maximum error tolerated in any one color channel in any one pixel before
    // a difference is reported.
    int colorThreshold = 0;
    SkString baseDir;
    SkString comparisonDir;
    SkString outputDir;

    StringArray matchSubstrings;
    StringArray nomatchSubstrings;

    bool generateDiffs = true;
    bool listFilenames = false;
    bool printDirNames = true;
    bool recurseIntoSubdirs = true;
    bool verbose = false;

    RecordArray differences;
    DiffSummary summary;

    bool failOnResultType[DiffRecord::kResultCount];
    for (int i = 0; i < DiffRecord::kResultCount; i++) {
        failOnResultType[i] = false;
    }

    bool failOnStatusType[DiffResource::kStatusCount][DiffResource::kStatusCount];
    for (int base = 0; base < DiffResource::kStatusCount; ++base) {
        for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
            failOnStatusType[base][comparison] = false;
        }
    }

    int i;
    int numUnflaggedArguments = 0;
    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "--failonresult")) {
            if (argc == ++i) {
                SkDebugf("failonresult expects one argument.\n");
                continue;
            }
            DiffRecord::Result type = DiffRecord::getResultByName(argv[i]);
            if (type != DiffRecord::kResultCount) {
                failOnResultType[type] = true;
            } else {
                SkDebugf("ignoring unrecognized result <%s>\n", argv[i]);
            }
            continue;
        }
        if (!strcmp(argv[i], "--failonstatus")) {
            if (argc == ++i) {
                SkDebugf("failonstatus missing base status.\n");
                continue;
            }
            bool baseStatuses[DiffResource::kStatusCount];
            if (!DiffResource::getMatchingStatuses(argv[i], baseStatuses)) {
                SkDebugf("unrecognized base status <%s>\n", argv[i]);
            }

            if (argc == ++i) {
                SkDebugf("failonstatus missing comparison status.\n");
                continue;
            }
            bool comparisonStatuses[DiffResource::kStatusCount];
            if (!DiffResource::getMatchingStatuses(argv[i], comparisonStatuses)) {
                SkDebugf("unrecognized comarison status <%s>\n", argv[i]);
            }

            for (int base = 0; base < DiffResource::kStatusCount; ++base) {
                for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
                    failOnStatusType[base][comparison] |=
                        baseStatuses[base] && comparisonStatuses[comparison];
                }
            }
            continue;
        }
        if (!strcmp(argv[i], "--help")) {
            usage(argv[0]);
            return kNoError;
        }
        if (!strcmp(argv[i], "--listfilenames")) {
            listFilenames = true;
            continue;
        }
        if (!strcmp(argv[i], "--verbose")) {
            verbose = true;
            continue;
        }
        if (!strcmp(argv[i], "--match")) {
            matchSubstrings.push(new SkString(argv[++i]));
            continue;
        }
        if (!strcmp(argv[i], "--nodiffs")) {
            generateDiffs = false;
            continue;
        }
        if (!strcmp(argv[i], "--nomatch")) {
            nomatchSubstrings.push(new SkString(argv[++i]));
            continue;
        }
        if (!strcmp(argv[i], "--noprintdirs")) {
            printDirNames = false;
            continue;
        }
        if (!strcmp(argv[i], "--norecurse")) {
            recurseIntoSubdirs = false;
            continue;
        }
        if (!strcmp(argv[i], "--sortbymaxmismatch")) {
            sortProc = compare<CompareDiffMaxMismatches>;
            continue;
        }
        if (!strcmp(argv[i], "--sortbymismatch")) {
            sortProc = compare<CompareDiffMeanMismatches>;
            continue;
        }
        if (!strcmp(argv[i], "--threshold")) {
            colorThreshold = atoi(argv[++i]);
            continue;
        }
        if (!strcmp(argv[i], "--weighted")) {
            sortProc = compare<CompareDiffWeighted>;
            continue;
        }
        if (argv[i][0] != '-') {
            switch (numUnflaggedArguments++) {
                case 0:
                    baseDir.set(argv[i]);
                    continue;
                case 1:
                    comparisonDir.set(argv[i]);
                    continue;
                case 2:
                    outputDir.set(argv[i]);
                    continue;
                default:
                    SkDebugf("extra unflagged argument <%s>\n", argv[i]);
                    usage(argv[0]);
                    return kGenericError;
            }
        }

        SkDebugf("Unrecognized argument <%s>\n", argv[i]);
        usage(argv[0]);
        return kGenericError;
    }

    if (numUnflaggedArguments == 2) {
        outputDir = comparisonDir;
    } else if (numUnflaggedArguments != 3) {
        usage(argv[0]);
        return kGenericError;
    }

    if (!baseDir.endsWith(PATH_DIV_STR)) {
        baseDir.append(PATH_DIV_STR);
    }
    if (printDirNames) {
        printf("baseDir is [%s]\n", baseDir.c_str());
    }

    if (!comparisonDir.endsWith(PATH_DIV_STR)) {
        comparisonDir.append(PATH_DIV_STR);
    }
    if (printDirNames) {
        printf("comparisonDir is [%s]\n", comparisonDir.c_str());
    }

    if (!outputDir.endsWith(PATH_DIV_STR)) {
        outputDir.append(PATH_DIV_STR);
    }
    if (generateDiffs) {
        if (printDirNames) {
            printf("writing diffs to outputDir is [%s]\n", outputDir.c_str());
        }
    } else {
        if (printDirNames) {
            printf("not writing any diffs to outputDir [%s]\n", outputDir.c_str());
        }
        outputDir.set("");
    }

    // If no matchSubstrings were specified, match ALL strings
    // (except for whatever nomatchSubstrings were specified, if any).
    if (matchSubstrings.isEmpty()) {
        matchSubstrings.push(new SkString(""));
    }

    create_diff_images(diffProc, colorThreshold, &differences,
                       baseDir, comparisonDir, outputDir,
                       matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, generateDiffs,
                       verbose, &summary);
    summary.print(listFilenames, failOnResultType, failOnStatusType);

    if (differences.count()) {
        qsort(differences.begin(), differences.count(),
              sizeof(DiffRecord*), sortProc);
    }

    if (generateDiffs) {
        print_diff_page(summary.fNumMatches, colorThreshold, differences,
                        baseDir, comparisonDir, outputDir);
    }

    for (i = 0; i < differences.count(); i++) {
        delete differences[i];
    }
    matchSubstrings.deleteAll();
    nomatchSubstrings.deleteAll();

    int num_failing_results = 0;
    for (int i = 0; i < DiffRecord::kResultCount; i++) {
        if (failOnResultType[i]) {
            num_failing_results += summary.fResultsOfType[i].count();
        }
    }
    if (!failOnResultType[DiffRecord::kCouldNotCompare_Result]) {
        for (int base = 0; base < DiffResource::kStatusCount; ++base) {
            for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
                if (failOnStatusType[base][comparison]) {
                    num_failing_results += summary.fStatusOfType[base][comparison].count();
                }
            }
        }
    }

    // On Linux (and maybe other platforms too), any results outside of the
    // range [0...255] are wrapped (mod 256).  Do the conversion ourselves, to
    // make sure that we only return 0 when there were no failures.
    return (num_failing_results > 255) ? 255 : num_failing_results;
}
Example #29
0
SkString* SkObjectParser::RRectToString(const SkRRect& rrect, const char* title) {

    SkString* mRRect = new SkString;

    if (nullptr == title) {
        mRRect->append("SkRRect (");
        if (rrect.isEmpty()) {
            mRRect->append("empty");
        } else if (rrect.isRect()) {
            mRRect->append("rect");
        } else if (rrect.isOval()) {
            mRRect->append("oval");
        } else if (rrect.isSimple()) {
            mRRect->append("simple");
        } else if (rrect.isNinePatch()) {
            mRRect->append("nine-patch");
        } else {
            SkASSERT(rrect.isComplex());
            mRRect->append("complex");
        }
        mRRect->append("): ");
    } else {
        mRRect->append(title);
    }
    mRRect->append("(");
    mRRect->appendScalar(rrect.rect().left());
    mRRect->append(", ");
    mRRect->appendScalar(rrect.rect().top());
    mRRect->append(", ");
    mRRect->appendScalar(rrect.rect().right());
    mRRect->append(", ");
    mRRect->appendScalar(rrect.rect().bottom());
    mRRect->append(") radii: (");
    for (int i = 0; i < 4; ++i) {
        const SkVector& radii = rrect.radii((SkRRect::Corner) i);
        mRRect->appendScalar(radii.fX);
        mRRect->append(", ");
        mRRect->appendScalar(radii.fY);
        if (i < 3) {
            mRRect->append(", ");
        }
    }
    mRRect->append(")");
    return mRRect;
}
Example #30
0
bool
SkFontData::checkCertify( bool system )
{
    SkString fullPathFontApp;
    SkStream * stFontApp = NULL;
    SkStream * stFont = NULL;
    SkStream * stDat = NULL;
    SkStream * stXml = NULL;
    skhycertified _hy_dat;

    fullPathFontApp.set( SYSTEM_DL_FONTAPP_SRC_DIR );
    fullPathFontApp.append( mFontAppName );

    if( system == true )
    {
        if( ( stFontApp = openReadStream( fullPathFontApp.c_str() ) ) == NULL )
        {
            HyLogif( "%s, not exist", fullPathFontApp.c_str() );
            goto ERROR0;
        }
        SkDELETE( stFontApp );
        stFontApp = NULL;
    }

    if( ( stFont = openReadStream( mFontFullPath ) ) == NULL )
    {
        HyLogif( "%s, not exist", mFontFullPath  );
        goto ERROR0;
    }
    SkDELETE( stFont );
    stFont = NULL;

    if( ( stXml = openReadStream( mFontXmlPath ) ) == NULL )
    {
        HyLogif( "%s, not exist", mFontXmlPath  );
        goto ERROR0;
    }
    SkDELETE( stXml );
    stXml = NULL;

    if( ( stDat = openReadStream( mFontDatPath ) ) == NULL )
    {
        HyLogif( "%s, not exist", mFontDatPath  );
        goto ERROR0;
    }

    if( __certified_check( &_hy_dat, stDat, mFontFullPath ) == false )
    {
        HyLogif( "%s, verification fails", fullPathFontApp.c_str() );
        goto ERROR0;
    }

    memcpy( mFontName, _hy_dat.key7_str, ( _hy_dat.key7 + 1 ) );
    __done_dat( &_hy_dat );
    SkDELETE( stDat );

    return setCertify( true );

ERROR0:
    if( stFontApp )
        SkDELETE( stFontApp );

    if( stFont )
        SkDELETE( stFont );

    if( stDat )
        SkDELETE( stDat );

    if( stXml )
        SkDELETE( stXml );

    return setCertify( false );
}