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(); }
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); }
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()); }
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()); } }
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; }
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 }
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(); }
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 ); }
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; } } }
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; }
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; }
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; }
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); }
static SkString make_png_name(const char* filename) { SkString pngName = SkString(filename); pngName.remove(pngName.size() - 3, 3); pngName.append("png"); return pngName; }
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; }
/** * 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); } }
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; }
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; }
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; }
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; }
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 ); }