static void showPath(const SkPath& path, const char* pathName, bool includeDeclaration) { SkPath::RawIter iter(path); #define SUPPORT_RECT_CONTOUR_DETECTION 0 #if SUPPORT_RECT_CONTOUR_DETECTION int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0; if (rectCount > 0) { SkTDArray<SkRect> rects; SkTDArray<SkPath::Direction> directions; rects.setCount(rectCount); directions.setCount(rectCount); path.rectContours(rects.begin(), directions.begin()); for (int contour = 0; contour < rectCount; ++contour) { const SkRect& rect = rects[contour]; SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction"); } return; } #endif SkPath::FillType fillType = path.getFillType(); SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType); if (includeDeclaration) { SkDebugf(" SkPath %s;\n", pathName); } SkDebugf(" %s.setFillType(SkPath::%s);\n", pathName, gFillTypeStr[fillType]); iter.setPath(path); showPathContours(iter, pathName); }
void initializeTests(skiatest::Reporter* reporter, const char* test) { #if 0 // doesn't work yet SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); SK_CONF_SET("images.png.suppressDecoderWarnings", true); #endif if (reporter->verbose()) { SkAutoMutexAcquire lock(gMutex); testName = test; size_t testNameSize = strlen(test); SkFILEStream inFile("../../experimental/Intersection/op.htm"); if (inFile.isValid()) { SkTDArray<char> inData; inData.setCount((int) inFile.getLength()); size_t inLen = inData.count(); inFile.read(inData.begin(), inLen); inFile.setPath(nullptr); char* insert = strstr(inData.begin(), marker); if (insert) { insert += sizeof(marker) - 1; const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1; testNumber = atoi(numLoc) + 1; } } } }
void draw(SkCanvas* canvas) { SkPath path, copy; path.lineTo(6.f / 7, 2.f / 3); size_t size = path.writeToMemory(nullptr); SkTDArray<char> storage; storage.setCount(size); path.writeToMemory(storage.begin()); copy.readFromMemory(storage.begin(), size); SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not "); }
void showPath(const SkPath& path, const char* str) { SkDebugf("%s\n", !str ? "original:" : str); SkPath::Iter iter(path, true); int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0; if (rectCount > 0) { SkTDArray<SkRect> rects; SkTDArray<SkPath::Direction> directions; rects.setCount(rectCount); directions.setCount(rectCount); path.rectContours(rects.begin(), directions.begin()); for (int contour = 0; contour < rectCount; ++contour) { const SkRect& rect = rects[contour]; SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction"); } return; } iter.setPath(path, true); showPathContour(iter); }
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) { SkIRect adjustedQuery = query; // The inset is to counteract the outset that was applied in 'insert' // The outset/inset is to optimize for lookups of size // 'tileInterval + 2 * margin' that are aligned with the tile grid. adjustedQuery.inset(fInfo.fMargin.width(), fInfo.fMargin.height()); adjustedQuery.offset(fInfo.fOffset); adjustedQuery.sort(); // in case the inset inverted the rectangle // Convert the query rectangle from device coordinates to tile coordinates // by rounding outwards to the nearest tile boundary so that the resulting tile // region includes the query rectangle. (using truncating division to "floor") int tileStartX = adjustedQuery.left() / fInfo.fTileInterval.width(); int tileEndX = (adjustedQuery.right() + fInfo.fTileInterval.width() - 1) / fInfo.fTileInterval.width(); int tileStartY = adjustedQuery.top() / fInfo.fTileInterval.height(); int tileEndY = (adjustedQuery.bottom() + fInfo.fTileInterval.height() - 1) / fInfo.fTileInterval.height(); tileStartX = SkPin32(tileStartX, 0, fXTileCount - 1); tileEndX = SkPin32(tileEndX, tileStartX+1, fXTileCount); tileStartY = SkPin32(tileStartY, 0, fYTileCount - 1); tileEndY = SkPin32(tileEndY, tileStartY+1, fYTileCount); int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY); SkASSERT(queryTileCount); if (queryTileCount == 1) { *results = this->tile(tileStartX, tileStartY); } else { results->reset(); SkTDArray<int> curPositions; curPositions.setCount(queryTileCount); // Note: Reserving space for 1024 tile pointers on the stack. If the // malloc becomes a bottleneck, we may consider increasing that number. // Typical large web page, say 2k x 16k, would require 512 tiles of // size 256 x 256 pixels. SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount); SkTDArray<void *>** tileRange = storage.get(); int tile = 0; for (int x = tileStartX; x < tileEndX; ++x) { for (int y = tileStartY; y < tileEndY; ++y) { tileRange[tile] = &this->tile(x, y); curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished; ++tile; } } void *nextElement; while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) { results->push(nextElement); } } }
bool SkConcaveToTriangles(size_t numPts, const SkPoint pts[], SkTDArray<SkPoint> *triangles) { DebugPrintf("SkConcaveToTriangles()\n"); SkTDArray<Vertex> vertices; vertices.setCount(numPts); if (!ConvertPointsToVertices(numPts, pts, vertices.begin())) return false; triangles->setReserve(numPts); triangles->setCount(0); return Triangulate(vertices.begin(), vertices.end() - 1, triangles); }
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) { SkIRect adjustedQuery = query; adjustedQuery.inset(fInfo.fMargin.width(), fInfo.fMargin.height()); adjustedQuery.offset(fInfo.fOffset); // Convert the query rectangle from device coordinates to tile coordinates // by rounding outwards to the nearest tile boundary so that the resulting tile // region includes the query rectangle. (using truncating division to "floor") int tileStartX = adjustedQuery.left() / fInfo.fTileInterval.width(); int tileEndX = (adjustedQuery.right() + fInfo.fTileInterval.width() - 1) / fInfo.fTileInterval.width(); int tileStartY = adjustedQuery.top() / fInfo.fTileInterval.height(); int tileEndY = (adjustedQuery.bottom() + fInfo.fTileInterval.height() - 1) / fInfo.fTileInterval.height(); if (tileStartX >= fXTileCount || tileStartY >= fYTileCount || tileEndX <= 0 || tileEndY <= 0) { return; // query does not intersect the grid } // clamp to grid if (tileStartX < 0) tileStartX = 0; if (tileStartY < 0) tileStartY = 0; if (tileEndX > fXTileCount) tileEndX = fXTileCount; if (tileEndY > fYTileCount) tileEndY = fYTileCount; int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY); if (queryTileCount == 1) { *results = this->tile(tileStartX, tileStartY); } else { results->reset(); SkTDArray<int> curPositions; curPositions.setCount(queryTileCount); // Note: Reserving space for 1024 tile pointers on the stack. If the // malloc becomes a bottleneck, we may consider increasing that number. // Typical large web page, say 2k x 16k, would require 512 tiles of // size 256 x 256 pixels. SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount); SkTDArray<void *>** tileRange = storage.get(); int tile = 0; for (int x = tileStartX; x < tileEndX; ++x) { for (int y = tileStartY; y < tileEndY; ++y) { tileRange[tile] = &this->tile(x, y); curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished; ++tile; } } void *nextElement; while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) { results->push(nextElement); } } }
static bool contains_only_moveTo(const SkPath& path) { int verbCount = path.countVerbs(); if (verbCount == 0) { return true; } SkTDArray<uint8_t> verbs; verbs.setCount(verbCount); SkDEBUGCODE(int getVerbResult = ) path.getVerbs(verbs.begin(), verbCount); SkASSERT(getVerbResult == verbCount); for (int index = 0; index < verbCount; ++index) { if (verbs[index] != SkPath::kMove_Verb) { return false; } } return true; }
int SkWGLExtensions::selectFormat(const int formats[], int formatCount, HDC dc, int desiredSampleCount) { PixelFormat desiredFormat = { 0, desiredSampleCount, 0, 0, }; SkTDArray<PixelFormat> rankedFormats; rankedFormats.setCount(formatCount); bool supportsCoverage = this->hasExtension(dc, "WGL_NV_multisample_coverage"); for (int i = 0; i < formatCount; ++i) { static const int queryAttrs[] = { SK_WGL_COVERAGE_SAMPLES, // Keep COLOR_SAMPLES at the end so it can be skipped SK_WGL_COLOR_SAMPLES, }; int answers[2]; int queryAttrCnt = supportsCoverage ? SK_ARRAY_COUNT(queryAttrs) : SK_ARRAY_COUNT(queryAttrs) - 1; this->getPixelFormatAttribiv(dc, formats[i], 0, queryAttrCnt, queryAttrs, answers); rankedFormats[i].fFormat = formats[i]; rankedFormats[i].fCoverageSamples = answers[0]; rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0]; rankedFormats[i].fChoosePixelFormatRank = i; } SkTQSort(rankedFormats.begin(), rankedFormats.begin() + rankedFormats.count() - 1, SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>()); int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(), rankedFormats.count(), desiredFormat, sizeof(PixelFormat)); if (idx < 0) { idx = ~idx; } return rankedFormats[idx].fFormat; }
void initializeTests(const char* test, size_t testNameSize) { testName = test; if (!gRunTestsInOneThread) { int threads = -1; size_t size = sizeof(threads); sysctlbyname("hw.logicalcpu_max", &threads, &size, NULL, 0); if (threads > 0) { maxThreads = threads; } else { maxThreads = 8; } } SkFILEStream inFile("../../experimental/Intersection/op.htm"); if (inFile.isValid()) { SkTDArray<char> inData; inData.setCount(inFile.getLength()); size_t inLen = inData.count(); inFile.read(inData.begin(), inLen); inFile.setPath(NULL); char* insert = strstr(inData.begin(), marker); if (insert) { insert += sizeof(marker) - 1; const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1; testNumber = atoi(numLoc) + 1; } } const char* filename = preferredFilename; SkFILEWStream preferredTest(filename); if (!preferredTest.isValid()) { filename = backupFilename; SkFILEWStream backupTest(filename); SkASSERT(backupTest.isValid()); } for (int index = 0; index < maxThreads; ++index) { State4* statePtr = &threadState[index]; strcpy(statePtr->filename, filename); size_t len = strlen(filename); SkASSERT(statePtr->filename[len - 6] == 'X'); SkASSERT(statePtr->filename[len - 5] == 'X'); statePtr->filename[len - 6] = '0' + index / 10; statePtr->filename[len - 5] = '0' + index % 10; } threadIndex = 0; }
static uint32_t compute_checksum(const SkTypeface* tf) { SkFontData* fontData = tf->createFontData(); if (!fontData) { return 0; } SkStreamAsset* fontStream = fontData->getStream(); if (!fontStream) { return 0; } SkTDArray<char> data; size_t length = fontStream->getLength(); if (!length) { return 0; } data.setCount((int) length); if (!fontStream->peek(data.begin(), length)) { return 0; } return SkChecksum::Murmur3(data.begin(), length); }
int SkWGLExtensions::selectFormat(const int formats[], int formatCount, HDC dc, int desiredSampleCount) const { if (formatCount <= 0) { return -1; } PixelFormat desiredFormat = { 0, desiredSampleCount, 0, }; SkTDArray<PixelFormat> rankedFormats; rankedFormats.setCount(formatCount); for (int i = 0; i < formatCount; ++i) { static const int kQueryAttr = SK_WGL_SAMPLES; int numSamples; this->getPixelFormatAttribiv(dc, formats[i], 0, 1, &kQueryAttr, &numSamples); rankedFormats[i].fFormat = formats[i]; rankedFormats[i].fSampleCnt = numSamples; rankedFormats[i].fChoosePixelFormatRank = i; } SkTQSort(rankedFormats.begin(), rankedFormats.begin() + rankedFormats.count() - 1, SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>()); int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(), rankedFormats.count(), desiredFormat, sizeof(PixelFormat)); if (idx < 0) { idx = ~idx; } return rankedFormats[idx].fFormat; }
// Enhance the polygon with trapezoids. bool ConvertPointsToVertices(size_t numPts, const SkPoint *pts, Vertex *vta) { DebugPrintf("ConvertPointsToVertices()\n"); // Clear everything. DebugPrintf("Zeroing vertices\n"); sk_bzero(vta, numPts * sizeof(*vta)); // Initialize vertices. DebugPrintf("Initializing vertices\n"); SetVertexPoints(numPts, pts, vta); InitializeVertexTopology(numPts, vta); PrintVertices(numPts, vta); SkTDArray<VertexPtr> vtptr; vtptr.setCount(numPts); for (int i = numPts; i-- != 0;) vtptr[i].vt = vta + i; PrintVertexPtrs(vtptr.count(), vtptr.begin(), vta); DebugPrintf("Sorting vertrap ptr array [%d] %p %p\n", vtptr.count(), &vtptr[0], &vtptr[vtptr.count() - 1] ); // SkTHeapSort(vtptr.begin(), vtptr.count()); BubbleSort(vtptr.begin(), vtptr.count()); DebugPrintf("Done sorting\n"); PrintVertexPtrs(vtptr.count(), vtptr.begin(), vta); DebugPrintf("Traversing sorted vertrap ptrs\n"); ActiveTrapezoids incompleteTrapezoids; for (VertexPtr *vtpp = vtptr.begin(); vtpp < vtptr.end(); ++vtpp) { DebugPrintf("%d: sorted vertrap %d\n", vtpp - vtptr.begin(), vtpp->vt - vta); Vertex *vt = vtpp->vt; Vertex *e0, *e1; Trapezoid *t; switch (vt->classify(&e0, &e1)) { case Vertex::MONOTONE: monotone: DebugPrintf("MONOTONE %d %d\n", e0 - vta, e1 - vta); // We should find one edge. t = incompleteTrapezoids.getTrapezoidWithEdge(e0); if (t == NULL) { // One of the edges is flat. DebugPrintf("Monotone: cannot find a trapezoid with e0: " "trying convex\n"); goto convex; } t->setBottom(vt); // This trapezoid is now complete. incompleteTrapezoids.remove(t); if (e0 == t->left()) // Replace the left edge. incompleteTrapezoids.insertNewTrapezoid(vt, e1, t->right()); else // Replace the right edge. incompleteTrapezoids.insertNewTrapezoid(vt, t->left(), e1); break; case Vertex::CONVEX: // Start of a new trapezoid. convex: // We don't expect to find any edges. DebugPrintf("CONVEX %d %d\n", e0 - vta, e1 - vta); if (incompleteTrapezoids.withinActiveTrapezoid( vt->point(), &t)) { // Complete trapezoid. SkASSERT(t != NULL); t->setBottom(vt); incompleteTrapezoids.remove(t); // Introduce two new trapezoids. incompleteTrapezoids.insertNewTrapezoid(vt, t->left(), e0); incompleteTrapezoids.insertNewTrapezoid(vt, e1, t->right()); } else { // Insert a new trapezoid. incompleteTrapezoids.insertNewTrapezoid(vt, e0, e1); } break; case Vertex::CONCAVE: // End of a trapezoid. DebugPrintf("CONCAVE %d %d\n", e0 - vta, e1 - vta); // We should find two edges. t = incompleteTrapezoids.getTrapezoidWithEdge(e0); if (t == NULL) { DebugPrintf("Concave: cannot find a trapezoid with e0: " " trying monotone\n"); goto monotone; } SkASSERT(t != NULL); if (e0 == t->left() && e1 == t->right()) { DebugPrintf( "Concave edges belong to the same trapezoid.\n"); // Edges belong to the same trapezoid. // Complete trapezoid & transfer it from the active list. t->setBottom(vt); incompleteTrapezoids.remove(t); } else { // Edges belong to different trapezoids DebugPrintf( "Concave edges belong to different trapezoids.\n"); // Complete left and right trapezoids. Trapezoid *s = incompleteTrapezoids.getTrapezoidWithEdge( e1); if (s == NULL) { DebugPrintf( "Concave: cannot find a trapezoid with e1: " " trying monotone\n"); goto monotone; } t->setBottom(vt); s->setBottom(vt); incompleteTrapezoids.remove(t); incompleteTrapezoids.remove(s); // Merge the two trapezoids into one below this vertex. incompleteTrapezoids.insertNewTrapezoid(vt, t->left(), s->right()); } break; } } RemoveDegenerateTrapezoids(numPts, vta); DebugPrintf("Done making trapezoids\n"); PrintVertexPtrs(vtptr.count(), vtptr.begin(), vta); size_t k = incompleteTrapezoids.count(); if (k > 0) { FailureMessage("%d incomplete trapezoids\n", k); return false; } return true; }
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"); }