bool SkAnimatorScript::IsFinite(const char* function, size_t len, SkTDArray<SkScriptValue>& params, void* eng, SkScriptValue* value) { if (SK_LITERAL_STR_EQUAL(function, "isFinite", len) == false) return false; if (params.count() != 1) return false; SkScriptValue* scriptValue = params.begin(); SkDisplayTypes type = scriptValue->fType; SkScalar scalar = scriptValue->fOperand.fScalar; value->fType = SkType_Int; value->fOperand.fS32 = type == SkType_Float ? SkScalarIsNaN(scalar) == false && SkScalarAbs(scalar) != SK_ScalarInfinity : type == SkType_Int; return true; }
static void add_name(const char name[], FamilyRec* family) { SkAutoAsciiToLC tolc(name); name = tolc.lc(); NameFamilyPair* list = gNameList.begin(); int count = gNameList.count(); int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); if (index < 0) { list = gNameList.insert(~index); list->construct(name, family); } }
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) { for (Draw** iter = fList.begin(); iter < fList.end(); iter++) { (*iter)->setSelected(false); } Click* c = new Click(this); Draw* d = this->hitTestList(x, y); if (d) { d->setSelected(true); c->setType("dragger"); } else { c->setType("maker"); } return c; }
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; }
static void drawdots(SkCanvas* canvas, const SkPaint& orig) { SkTDArray<SkPoint> pts; SkPathEffect* pe = makepe(0, &pts); SkScalar width = -1; SkPath path, dstPath; orig.getTextPath("9", 1, 0, 0, &path); pe->filterPath(&dstPath, path, &width); SkPaint p; p.setAntiAlias(true); p.setStrokeWidth(10); p.setColor(SK_ColorRED); canvas->drawPoints(SkCanvas::kPoints_PointMode, pts.count(), pts.begin(), p); }
void SampleWindow::loadView(SkView* view) { SkView::F2BIter iter(this); SkView* prev = iter.next(); if (prev) { prev->detachFromParent(); } if (NULL == view) { view = create_overview(fSamples.count(), fSamples.begin()); } view->setVisibleP(true); this->attachChildToFront(view)->unref(); view->setSize(this->width(), this->height()); this->updateTitle(); }
virtual void onDraw(SkCanvas* canvas) { this->drawBG(canvas); test_clearonlayers(canvas); return; // test_strokerect(canvas); return; for (Draw** iter = fList.begin(); iter < fList.end(); iter++) { (*iter)->draw(canvas); } if (fDraw) { fDraw->draw(canvas); } }
template <typename T> void SkRTConfRegistry::set(const char *name, T value) { SkTDArray<SkRTConfBase *> *confArray; if (!fConfs.find(name, &confArray)) { SkDebugf("WARNING: Attempting to set configuration value \"%s\", but I've never heard of that.\n", name); return; } for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) { // static_cast here is okay because there's only one kind of child class. SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase); if (concrete) { concrete->set(value); } } }
Trapezoid* ActiveTrapezoids::getTrapezoidWithEdge(const Vertex *edge) { DebugPrintf("Entering getTrapezoidWithEdge(): looking through %d\n", fTrapezoids.count()); DebugPrintf("trying to find %p: ", edge); Trapezoid **tp; for (tp = fTrapezoids.begin(); tp < fTrapezoids.end(); ++tp) { SkASSERT(tp != NULL); SkASSERT(*tp != NULL); DebugPrintf("%p and %p, ", (**tp).left(), (**tp).right()); if ((**tp).left() == edge || (**tp).right() == edge) { DebugPrintf("\ngetTrapezoidWithEdge found the trapezoid\n"); return *tp; } } DebugPrintf("getTrapezoidWithEdge found no trapezoid\n"); return NULL; }
bool SkAnimatorScript::Eval(const char* function, size_t len, SkTDArray<SkScriptValue>& params, void* eng, SkScriptValue* value) { if (SK_LITERAL_STR_EQUAL("eval", function, len) == false) return false; if (params.count() != 1) return false; SkAnimatorScript* host = (SkAnimatorScript*) eng; SkAnimatorScript engine(host->fMaker, host->fWorking, SkScriptEngine::ToDisplayType(host->fReturnType)); SkScriptValue* scriptValue = params.begin(); bool success = true; if (scriptValue->fType == SkType_String) { const char* script = scriptValue->fOperand.fString->c_str(); success = engine.evaluateScript(&script, value); } else *value = *scriptValue; return success; }
int SkPictureRecord::find(SkTDArray<const SkFlatPaint* >& paints, const SkPaint* paint) { if (paint == NULL) { return 0; } SkFlatPaint* flat = SkFlatPaint::Flatten(&fHeap, *paint, fPaintIndex, &fRCSet, &fTFSet); int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(), paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { (void)fHeap.unalloc(flat); return paints[index]->index(); } index = ~index; *paints.insert(index) = flat; return fPaintIndex++; }
bool SkAnimatorScript::EvalRGB(const char* function, size_t len, SkTDArray<SkScriptValue>& params, void* eng, SkScriptValue* value) { if (SK_LITERAL_STR_EQUAL("rgb", function, len) == false) return false; if (params.count() != 3) return false; SkScriptEngine* engine = (SkScriptEngine*) eng; unsigned result = 0xFF000000; int shift = 16; for (SkScriptValue* valuePtr = params.begin(); valuePtr < params.end(); valuePtr++) { engine->convertTo(SkType_Int, valuePtr); result |= SkClampMax(valuePtr->fOperand.fS32, 255) << shift; shift -= 8; } value->fOperand.fS32 = result; value->fType = SkType_Int; return true; }
virtual bool onClick(Click* click) { if (Click::kUp_State == click->fState) { if (click->isType("maker")) { if (SkPoint::Distance(click->fOrig, click->fCurr) > SkIntToScalar(3)) { *fList.append() = fDraw; } else { fDraw->unref(); } fDraw = NULL; } return true; } if (Click::kDown_State == click->fState) { SkPaint p = fFactory->getPaint(); p.setColor(this->randColor()); fFactory->setPaint(p); } if (click->isType("maker")) { this->setDraw(fFactory->create(click->fOrig, click->fCurr))->unref(); } else if (click->isType("dragger")) { for (Draw** iter = fList.begin(); iter < fList.end(); iter++) { if ((*iter)->isSelected()) { (*iter)->offset(click->fCurr.x() - click->fPrev.x(), click->fCurr.y() - click->fPrev.y()); } } } this->inval(NULL); return true; }
static void draw_path(SkCanvas* canvas, const SkPaint& pathPaint, const SkPath& path, const SkPaint& triPaint) { canvas->drawPath(path, pathPaint); int n = path.getPoints(NULL, 0); SkPoint* pts = new SkPoint[n]; path.getPoints(pts, n); SkTDArray<SkPoint> triangles; if (SkConcaveToTriangles(n, pts, &triangles)) { canvas->drawVertices(SkCanvas::kTriangles_VertexMode, triangles.count(), triangles.begin(), NULL, NULL, NULL, NULL, 0, triPaint); } SkPaint paint; paint.setColor(SK_ColorGREEN); paint.setStrokeWidth(SkIntToScalar(4)); canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts, paint); delete[] pts; }
void onDraw(int loops, SkCanvas* canvas) override { SkPaint paint; this->setupPaint(&paint); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(fWidth)); paint.setAntiAlias(false); SkPath path; this->makePath(&path); paint.setPathEffect(SkDashPathEffect::Create(fIntervals.begin(), fIntervals.count(), 0))->unref(); if (fDoClip) { SkRect r = path.getBounds(); r.inset(-SkIntToScalar(20), -SkIntToScalar(20)); // now move it so we don't intersect r.offset(0, r.height() * 3 / 2); canvas->clipRect(r); } this->handlePath(canvas, path, paint, loops); }
void SkRecordDraw(const SkRecord& record, SkCanvas* canvas, const SkBBoxHierarchy* bbh, SkDrawPictureCallback* callback) { SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); if (NULL != bbh) { // Draw only ops that affect pixels in the canvas's current clip. SkIRect devBounds; canvas->getClipDeviceBounds(&devBounds); SkTDArray<void*> ops; bbh->search(devBounds, &ops); // FIXME: QuadTree doesn't send these back in the order we inserted them. :( // Also remove the sort in SkPictureData::getActiveOps()? if (ops.count() > 0) { SkTQSort(ops.begin(), ops.end() - 1, SkTCompareLT<void*>()); } SkRecords::Draw draw(canvas); for (int i = 0; i < ops.count(); i++) { if (NULL != callback && callback->abortDrawing()) { return; } record.visit<void>((uintptr_t)ops[i], draw); // See FillBounds below. } } else { // Draw all ops. for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) { if (NULL != callback && callback->abortDrawing()) { return; } record.visit<void>(draw.index(), draw); } } }
static FamilyRec* find_familyrec(const char name[]) { const NameFamilyPair* list = gNameList.begin(); int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name, sizeof(list[0])); return index >= 0 ? list[index].fFamily : NULL; }
bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[], SkString* outFamilyName, SkTArray<FontIdentity>* ids) { SkAutoMutexAcquire ac(mutex_); #if 0 SkString familyStr(familyName ? familyName : ""); if (familyStr.size() > kMaxFontFamilyLength) { return false; } SkAutoMutexAcquire ac(mutex_); FcPattern* pattern = FcPatternCreate(); if (familyName) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); } FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Font matching: // CSS often specifies a fallback list of families: // font-family: a, b, c, serif; // However, fontconfig will always do its best to find *a* font when asked // for something so we need a way to tell if the match which it has found is // "good enough" for us. Otherwise, we can return NULL which gets piped up // and lets WebKit know to try the next CSS family name. However, fontconfig // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we // wish to support that. // // Thus, if a specific family is requested we set @family_requested. Then we // record two strings: the family name after config processing and the // family name after resolving. If the two are equal, it's a good match. // // So consider the case where a user has mapped Arial to Helvetica in their // config. // requested family: "Arial" // post_config_family: "Helvetica" // post_match_family: "Helvetica" // -> good match // // and for a missing font: // requested family: "Monaco" // post_config_family: "Monaco" // post_match_family: "Times New Roman" // -> BAD match // // However, we special-case fallback fonts; see IsFallbackFontAllowed(). const char* post_config_family = get_name(pattern, FC_FAMILY); FcResult result; FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); if (!font_set) { FcPatternDestroy(pattern); return false; } FcPattern* match = MatchFont(font_set, post_config_family, familyStr); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return false; } FcPatternDestroy(pattern); // From here out we just extract our results from 'match' if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FcChar8* c_filename; if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } int face_index; if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FcFontSetDestroy(font_set); if (outIdentity) { outIdentity->fTTCIndex = face_index; outIdentity->fString.set((const char*)c_filename); } if (outFamilyName) { outFamilyName->set((const char*)post_config_family); } if (outStyle) { *outStyle = GetFontStyle(match); } return true; //////////////////// int count; FcPattern** match = MatchFont(font_set, post_config_family, &count); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return NULL; } FcPatternDestroy(pattern); SkTDArray<FcPattern*> trimmedMatches; for (int i = 0; i < count; ++i) { const char* justName = find_just_name(get_name(match[i], FC_FILE)); if (!is_lower(*justName)) { *trimmedMatches.append() = match[i]; } } SkFontStyleSet_FC* sset = new SkFontStyleSet_FC (trimmedMatches.begin(), trimmedMatches.count()); #endif return false; }
/* check start and end of each contour if not the same, record them match them up connect closest reassemble contour pieces into new path */ void Assemble(const SkPathWriter& path, SkPathWriter* simple) { SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContourHead contour; SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(nullptr)); #if DEBUG_SHOW_TEST_NAME SkDebugf("</div>\n"); #endif #if DEBUG_PATH_CONSTRUCTION SkDebugf("%s\n", __FUNCTION__); #endif SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); builder.finish(&allocator); SkTDArray<const SkOpContour* > runs; // indices of partial contours const SkOpContour* eContour = builder.head(); do { if (!eContour->count()) { continue; } const SkPoint& eStart = eContour->start(); const SkPoint& eEnd = eContour->end(); #if DEBUG_ASSEMBLE SkDebugf("%s contour", __FUNCTION__); if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { SkDebugf("[%d]", runs.count()); } else { SkDebugf(" "); } SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); #endif if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { eContour->toPath(simple); continue; } *runs.append() = eContour; } while ((eContour = eContour->next())); int count = runs.count(); if (count == 0) { return; } SkTDArray<int> sLink, eLink; sLink.append(count); eLink.append(count); int rIndex, iIndex; for (rIndex = 0; rIndex < count; ++rIndex) { sLink[rIndex] = eLink[rIndex] = SK_MaxS32; } const int ends = count * 2; // all starts and ends const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 SkTDArray<double> distances; distances.append(entries); for (rIndex = 0; rIndex < ends - 1; ++rIndex) { const SkOpContour* oContour = runs[rIndex >> 1]; const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start(); const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) * ends - rIndex - 1; for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { const SkOpContour* iContour = runs[iIndex >> 1]; const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start(); double dx = iPt.fX - oPt.fX; double dy = iPt.fY - oPt.fY; double dist = dx * dx + dy * dy; distances[row + iIndex] = dist; // oStart distance from iStart } } SkTDArray<int> sortedDist; sortedDist.append(entries); for (rIndex = 0; rIndex < entries; ++rIndex) { sortedDist[rIndex] = rIndex; } SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); int remaining = count; // number of start/end pairs for (rIndex = 0; rIndex < entries; ++rIndex) { int pair = sortedDist[rIndex]; int row = pair / ends; int col = pair - row * ends; int thingOne = row < col ? row : ends - row - 2; int ndxOne = thingOne >> 1; bool endOne = thingOne & 1; int* linkOne = endOne ? eLink.begin() : sLink.begin(); if (linkOne[ndxOne] != SK_MaxS32) { continue; } int thingTwo = row < col ? col : ends - row + col - 1; int ndxTwo = thingTwo >> 1; bool endTwo = thingTwo & 1; int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); if (linkTwo[ndxTwo] != SK_MaxS32) { continue; } SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); bool flip = endOne == endTwo; linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; if (!--remaining) { break; } } SkASSERT(!remaining); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { int s = sLink[rIndex]; int e = eLink[rIndex]; SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); } #endif rIndex = 0; do { bool forward = true; bool first = true; int sIndex = sLink[rIndex]; SkASSERT(sIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; int eIndex; if (sIndex < 0) { eIndex = sLink[~sIndex]; sLink[~sIndex] = SK_MaxS32; } else { eIndex = eLink[sIndex]; eLink[sIndex] = SK_MaxS32; } SkASSERT(eIndex != SK_MaxS32); #if DEBUG_ASSEMBLE SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', eIndex < 0 ? ~eIndex : eIndex); #endif do { const SkOpContour* contour = runs[rIndex]; if (first) { first = false; const SkPoint* startPtr = &contour->start(); simple->deferredMove(startPtr[0]); } if (forward) { contour->toPartialForward(simple); } else { contour->toPartialBackward(simple); } #if DEBUG_ASSEMBLE SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); #endif if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { simple->close(); break; } if (forward) { eIndex = eLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); eLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(sLink[eIndex] == rIndex); sLink[eIndex] = SK_MaxS32; } else { SkASSERT(eLink[~eIndex] == ~rIndex); eLink[~eIndex] = SK_MaxS32; } } else { eIndex = sLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(eLink[eIndex] == rIndex); eLink[eIndex] = SK_MaxS32; } else { SkASSERT(sLink[~eIndex] == ~rIndex); sLink[~eIndex] = SK_MaxS32; } } rIndex = eIndex; if (rIndex < 0) { forward ^= 1; rIndex = ~rIndex; } } while (true); for (rIndex = 0; rIndex < count; ++rIndex) { if (sLink[rIndex] != SK_MaxS32) { break; } } } while (rIndex < count); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { SkASSERT(sLink[rIndex] == SK_MaxS32); SkASSERT(eLink[rIndex] == SK_MaxS32); } #endif }
// 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; }
sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) { SkTextBlobBuilder builder; SkFont font; font.setSubpixel(true); font.setEdging(SkFont::Edging::kAntiAlias); font.setTypeface(fTypeface); for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) { unsigned currentGlyph = 0; for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) { const BlobCfg* cfg = &blobConfigs[blobIndex][l][c]; unsigned count = cfg->count; if (count > fGlyphs.count() - currentGlyph) { count = fGlyphs.count() - currentGlyph; } if (0 == count) { break; } font.setSize(kFontSize * cfg->scale); const SkScalar advanceX = font.getSize() * 0.85f; const SkScalar advanceY = font.getSize() * 1.5f; SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX, advanceY * l); switch (cfg->pos) { case kDefault_Pos: { const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count, offset.x(), offset.y()); memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); } break; case kScalar_Pos: { const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count, offset.y()); SkTDArray<SkScalar> pos; for (unsigned i = 0; i < count; ++i) { *pos.append() = offset.x() + i * advanceX; } memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar)); } break; case kPoint_Pos: { const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count); SkTDArray<SkScalar> pos; for (unsigned i = 0; i < count; ++i) { *pos.append() = offset.x() + i * advanceX; *pos.append() = offset.y() + i * (advanceY / count); } memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2); } break; default: SK_ABORT("unhandled pos value"); } currentGlyph += count; } } return builder.make(); }
void ImGuiLayer::onPaint(SkSurface* surface) { // This causes ImGui to rebuild vertex/index data based on all immediate-mode commands // (widgets, etc...) that have been issued ImGui::Render(); // Then we fetch the most recent data, and convert it so we can render with Skia const ImDrawData* drawData = ImGui::GetDrawData(); SkTDArray<SkPoint> pos; SkTDArray<SkPoint> uv; SkTDArray<SkColor> color; auto canvas = surface->getCanvas(); for (int i = 0; i < drawData->CmdListsCount; ++i) { const ImDrawList* drawList = drawData->CmdLists[i]; // De-interleave all vertex data (sigh), convert to Skia types pos.rewind(); uv.rewind(); color.rewind(); for (int j = 0; j < drawList->VtxBuffer.size(); ++j) { const ImDrawVert& vert = drawList->VtxBuffer[j]; pos.push_back(SkPoint::Make(vert.pos.x, vert.pos.y)); uv.push_back(SkPoint::Make(vert.uv.x, vert.uv.y)); color.push_back(vert.col); } // ImGui colors are RGBA SkSwapRB(color.begin(), color.begin(), color.count()); int indexOffset = 0; // Draw everything with canvas.drawVertices... for (int j = 0; j < drawList->CmdBuffer.size(); ++j) { const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j]; SkAutoCanvasRestore acr(canvas, true); // TODO: Find min/max index for each draw, so we know how many vertices (sigh) if (drawCmd->UserCallback) { drawCmd->UserCallback(drawList, drawCmd); } else { intptr_t idIndex = (intptr_t)drawCmd->TextureId; if (idIndex < fSkiaWidgetFuncs.count()) { // Small image IDs are actually indices into a list of callbacks. We directly // examing the vertex data to deduce the image rectangle, then reconfigure the // canvas to be clipped and translated so that the callback code gets to use // Skia to render a widget in the middle of an ImGui panel. ImDrawIdx rectIndex = drawList->IdxBuffer[indexOffset]; SkPoint tl = pos[rectIndex], br = pos[rectIndex + 2]; canvas->clipRect(SkRect::MakeLTRB(tl.fX, tl.fY, br.fX, br.fY)); canvas->translate(tl.fX, tl.fY); fSkiaWidgetFuncs[idIndex](canvas); } else { SkPaint* paint = static_cast<SkPaint*>(drawCmd->TextureId); SkASSERT(paint); canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y, drawCmd->ClipRect.z, drawCmd->ClipRect.w)); auto vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, drawList->VtxBuffer.size(), pos.begin(), uv.begin(), color.begin(), drawCmd->ElemCount, drawList->IdxBuffer.begin() + indexOffset); canvas->drawVertices(vertices, SkBlendMode::kModulate, *paint); } indexOffset += drawCmd->ElemCount; } } } fSkiaWidgetFuncs.reset(); }
void SkDisplayMath::executeFunction(SkDisplayable* target, int index, SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, SkScriptValue* scriptValue) { if (scriptValue == NULL) return; SkASSERT(target == this); SkScriptValue* array = parameters.begin(); SkScriptValue* end = parameters.end(); SkScalar input = parameters[0].fOperand.fScalar; SkScalar scalarResult; switch (index) { case SK_FUNCTION(abs): scalarResult = SkScalarAbs(input); break; case SK_FUNCTION(acos): scalarResult = SkScalarACos(input); break; case SK_FUNCTION(asin): scalarResult = SkScalarASin(input); break; case SK_FUNCTION(atan): scalarResult = SkScalarATan2(input, SK_Scalar1); break; case SK_FUNCTION(atan2): scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar); break; case SK_FUNCTION(ceil): scalarResult = SkIntToScalar(SkScalarCeil(input)); break; case SK_FUNCTION(cos): scalarResult = SkScalarCos(input); break; case SK_FUNCTION(exp): scalarResult = SkScalarExp(input); break; case SK_FUNCTION(floor): scalarResult = SkIntToScalar(SkScalarFloor(input)); break; case SK_FUNCTION(log): scalarResult = SkScalarLog(input); break; case SK_FUNCTION(max): scalarResult = -SK_ScalarMax; while (array < end) { scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(min): scalarResult = SK_ScalarMax; while (array < end) { scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(pow): // not the greatest -- but use x^y = e^(y * ln(x)) scalarResult = SkScalarLog(input); scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult); scalarResult = SkScalarExp(scalarResult); break; case SK_FUNCTION(random): scalarResult = fRandom.nextUScalar1(); break; case SK_FUNCTION(round): scalarResult = SkIntToScalar(SkScalarRound(input)); break; case SK_FUNCTION(sin): scalarResult = SkScalarSin(input); break; case SK_FUNCTION(sqrt): { SkASSERT(parameters.count() == 1); SkASSERT(type == SkType_Float); scalarResult = SkScalarSqrt(input); } break; case SK_FUNCTION(tan): scalarResult = SkScalarTan(input); break; default: SkASSERT(0); scalarResult = SK_ScalarNaN; } scriptValue->fOperand.fScalar = scalarResult; scriptValue->fType = SkType_Float; }
// intersect the end of the cubic with the other. Try lines from the end to control and opposite // end to determine range of t on opposite cubic. static bool intersectEnd(const Cubic& cubic1, bool start, const Cubic& cubic2, const _Rect& bounds2, Intersections& i) { // bool selfIntersect = cubic1 == cubic2; _Line line; int t1Index = start ? 0 : 3; line[0] = cubic1[t1Index]; // don't bother if the two cubics are connnected #if 0 if (!selfIntersect && (line[0].approximatelyEqual(cubic2[0]) || line[0].approximatelyEqual(cubic2[3]))) { return false; } #endif bool result = false; SkTDArray<double> tVals; // OPTIMIZE: replace with hard-sized array for (int index = 0; index < 4; ++index) { if (index == t1Index) { continue; } _Vector dxy1 = cubic1[index] - line[0]; dxy1 /= gPrecisionUnit; line[1] = line[0] + dxy1; _Rect lineBounds; lineBounds.setBounds(line); if (!bounds2.intersects(lineBounds)) { continue; } Intersections local; if (!intersect(cubic2, line, local)) { continue; } for (int idx2 = 0; idx2 < local.used(); ++idx2) { double foundT = local.fT[0][idx2]; if (approximately_less_than_zero(foundT) || approximately_greater_than_one(foundT)) { continue; } if (local.fPt[idx2].approximatelyEqual(line[0])) { if (i.swapped()) { // FIXME: insert should respect swap i.insert(foundT, start ? 0 : 1, line[0]); } else { i.insert(start ? 0 : 1, foundT, line[0]); } result = true; } else { *tVals.append() = local.fT[0][idx2]; } } } if (tVals.count() == 0) { return result; } QSort<double>(tVals.begin(), tVals.end() - 1); double tMin1 = start ? 0 : 1 - LINE_FRACTION; double tMax1 = start ? LINE_FRACTION : 1; int tIdx = 0; do { int tLast = tIdx; while (tLast + 1 < tVals.count() && roughly_equal(tVals[tLast + 1], tVals[tIdx])) { ++tLast; } double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0); double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0); int lastUsed = i.used(); result |= intersect3(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); if (lastUsed == i.used()) { tMin2 = SkTMax(tVals[tIdx] - (1.0 / gPrecisionUnit), 0.0); tMax2 = SkTMin(tVals[tLast] + (1.0 / gPrecisionUnit), 1.0); result |= intersect3(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); } tIdx = tLast + 1; } while (tIdx < tVals.count()); return result; }
void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrBatchFontCache* fontCache, const SkSurfaceProps& props, const SkPaint& origPaint, GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != nullptr); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); // nothing to draw if (text == nullptr || byteLength == 0) { return; } SkTDArray<char> fallbackTxt; SkTDArray<SkScalar> fallbackPos; // Setup distance field paint and text ratio SkScalar textRatio; SkPaint dfPaint(origPaint); GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix); blob->setHasDistanceField(); blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText()); GrBatchTextStrike* currStrike = nullptr; SkGlyphCache* cache = blob->setupCache(runIndex, props, SkPaint::FakeGamma::Off, dfPaint, nullptr); SkPaint::GlyphCacheProc glyphCacheProc = dfPaint.getGlyphCacheProc(true); GrFontScaler* fontScaler = GrTextUtils::GetGrFontScaler(cache); const char* stop = text + byteLength; if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) { while (text < stop) { const char* lastText = text; // the last 2 parameters are ignored const SkGlyph& glyph = glyphCacheProc(cache, &text); if (glyph.fWidth) { SkScalar x = offset.x() + pos[0]; SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x, y, color, fontScaler, textRatio, viewMatrix)) { // couldn't append, send to fallback fallbackTxt.append(SkToInt(text-lastText), lastText); *fallbackPos.append() = pos[0]; if (2 == scalarsPerPosition) { *fallbackPos.append() = pos[1]; } } } pos += scalarsPerPosition; } } else { SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? SK_ScalarHalf : SK_Scalar1; while (text < stop) { const char* lastText = text; // the last 2 parameters are ignored const SkGlyph& glyph = glyphCacheProc(cache, &text); if (glyph.fWidth) { SkScalar x = offset.x() + pos[0]; SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio; SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio; if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x - advanceX, y - advanceY, color, fontScaler, textRatio, viewMatrix)) { // couldn't append, send to fallback fallbackTxt.append(SkToInt(text-lastText), lastText); *fallbackPos.append() = pos[0]; if (2 == scalarsPerPosition) { *fallbackPos.append() = pos[1]; } } } pos += scalarsPerPosition; } } SkGlyphCache::AttachCache(cache); if (fallbackTxt.count()) { blob->initOverride(runIndex); GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props, origPaint, origPaint.getColor(), viewMatrix, fallbackTxt.begin(), fallbackTxt.count(), fallbackPos.begin(), scalarsPerPosition, offset); } }
int dm_main() { SetupCrashHandler(); SkAutoGraphics ag; SkTaskGroup::Enabler enabled(FLAGS_threads); gCreateTypefaceDelegate = &create_from_name; start_keepalive(); gather_gold(); gather_uninteresting_hashes(); gather_srcs(); gather_sinks(); gather_tests(); gPending = gSrcs.count() * gSinks.count() + gThreadedTests.count() + gGPUTests.count(); SkDebugf("%d srcs * %d sinks + %d tests == %d tasks\n", gSrcs.count(), gSinks.count(), gThreadedTests.count() + gGPUTests.count(), gPending); // We try to exploit as much parallelism as is safe. Most Src/Sink pairs run on any thread, // but Sinks that identify as part of a particular enclave run serially on a single thread. // CPU tests run on any thread. GPU tests depend on --gpu_threading. SkTArray<Task> enclaves[kNumEnclaves]; for (int j = 0; j < gSinks.count(); j++) { SkTArray<Task>& tasks = enclaves[gSinks[j]->enclave()]; for (int i = 0; i < gSrcs.count(); i++) { tasks.push_back(Task(gSrcs[i], gSinks[j])); } } SkTaskGroup tg; tg.batch(run_test, gThreadedTests.begin(), gThreadedTests.count()); for (int i = 0; i < kNumEnclaves; i++) { switch(i) { case kAnyThread_Enclave: tg.batch(Task::Run, enclaves[i].begin(), enclaves[i].count()); break; case kGPU_Enclave: tg.add(run_enclave_and_gpu_tests, &enclaves[i]); break; default: tg.add(run_enclave, &enclaves[i]); break; } } tg.wait(); // At this point we're back in single-threaded land. sk_tool_utils::release_portable_typefaces(); SkDebugf("\n"); if (gFailures.count() > 0) { SkDebugf("Failures:\n"); for (int i = 0; i < gFailures.count(); i++) { SkDebugf("\t%s\n", gFailures[i].c_str()); } SkDebugf("%d failures\n", gFailures.count()); return 1; } if (gPending > 0) { SkDebugf("Hrm, we didn't seem to run everything we intended to! Please file a bug.\n"); return 1; } return 0; }
DEF_TEST(CanvasState_test_complex_clips, reporter) { const int WIDTH = 400; const int HEIGHT = 400; const int SPACER = 10; SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4); layerRect.inset(2*SPACER, 2*SPACER); SkIRect clipRect = layerRect; clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER); clipRect.outset(SPACER, SPACER); SkIRect regionBounds = clipRect; regionBounds.offset(clipRect.width() + (2*SPACER), 0); SkIRect regionInterior = regionBounds; regionInterior.inset(SPACER*3, SPACER*3); SkRegion clipRegion; clipRegion.setRect(regionBounds); clipRegion.op(regionInterior, SkRegion::kDifference_Op); const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op, SkRegion::kIntersect_Op, SkRegion::kReplace_Op, }; const SkCanvas::SaveLayerFlags flags[] = { static_cast<SkCanvas::SaveLayerFlags>(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag), 0, static_cast<SkCanvas::SaveLayerFlags>(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag), }; REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags)); bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t, int32_t r, int32_t b, int32_t clipOp, int32_t regionRects, int32_t* rectCoords); OpenLibResult openLibResult(reporter); if (openLibResult.handle() != nullptr) { *(void**) (&drawFn) = dlsym(openLibResult.handle(), "complex_clips_draw_from_canvas_state"); } else { drawFn = complex_clips_draw_from_canvas_state; } REPORTER_ASSERT(reporter, drawFn); if (!drawFn) { return; } SkBitmap bitmaps[2]; for (int i = 0; i < 2; ++i) { bitmaps[i].allocN32Pixels(WIDTH, HEIGHT); SkCanvas canvas(bitmaps[i]); canvas.drawColor(SK_ColorRED); SkRegion localRegion = clipRegion; SkPaint paint; paint.setAlpha(128); for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) { SkRect layerBounds = SkRect::Make(layerRect); canvas.saveLayer(SkCanvas::SaveLayerRec(&layerBounds, &paint, flags[j])); if (i) { SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas); REPORTER_ASSERT(reporter, state); SkRegion::Iterator iter(localRegion); SkTDArray<int32_t> rectCoords; for (; !iter.done(); iter.next()) { const SkIRect& rect = iter.rect(); *rectCoords.append() = rect.fLeft; *rectCoords.append() = rect.fTop; *rectCoords.append() = rect.fRight; *rectCoords.append() = rect.fBottom; } bool success = drawFn(state, clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, clipOps[j], rectCoords.count() / 4, rectCoords.begin()); REPORTER_ASSERT(reporter, success); SkCanvasStateUtils::ReleaseCanvasState(state); } else { complex_clips_draw(&canvas, clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, clipOps[j], localRegion); } canvas.restore(); // translate the canvas and region for the next iteration canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER)))); localRegion.translate(0, 2*(layerRect.height() + SPACER)); } } // now we memcmp the two bitmaps REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize()); REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(), bitmaps[1].getPixels(), bitmaps[0].getSize())); }