SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const { #ifdef SK_SCALAR_IS_FLOAT float mag = sk_float_sqrt(fX*fX + fY*fY + fZ*fZ); if (mag) { float scale = 1.0f / mag; unit->fX = fX * scale; unit->fY = fY * scale; unit->fZ = fZ * scale; } #else Sk64 tmp1, tmp2; tmp1.setMul(fX, fX); tmp2.setMul(fY, fY); tmp1.add(tmp2); tmp2.setMul(fZ, fZ); tmp1.add(tmp2); SkFixed mag = tmp1.getSqrt(); if (mag) { // what if mag < SK_Fixed1 ??? we will underflow the fixdiv SkFixed scale = SkFixedDiv(SK_Fract1, mag); unit->fX = SkFixedMul(fX, scale); unit->fY = SkFixedMul(fY, scale); unit->fZ = SkFixedMul(fZ, scale); } #endif return mag; }
// called from a curve subclass int SkEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1) { SkASSERT(fWinding == 1 || fWinding == -1); SkASSERT(fCurveCount != 0); // SkASSERT(fCurveShift != 0); y0 >>= 10; y1 >>= 10; SkASSERT(y0 <= y1); int top = SkFDot6Round(y0); int bot = SkFDot6Round(y1); // SkASSERT(top >= fFirstY); // are we a zero-height line? if (top == bot) return 0; x0 >>= 10; x1 >>= 10; SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0); const SkFDot6 dy = SkEdge_Compute_DY(top, y0); fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy)); // + SK_Fixed1/2 fDX = slope; fFirstY = top; fLastY = bot - 1; return 1; }
int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, int shift) { SkFDot6 x0, y0, x1, y1; { #ifdef SK_RASTERIZE_EVEN_ROUNDING x0 = SkScalarRoundToFDot6(p0.fX, shift); y0 = SkScalarRoundToFDot6(p0.fY, shift); x1 = SkScalarRoundToFDot6(p1.fX, shift); y1 = SkScalarRoundToFDot6(p1.fY, shift); #else float scale = float(1 << (shift + 6)); x0 = int(p0.fX * scale); y0 = int(p0.fY * scale); x1 = int(p1.fX * scale); y1 = int(p1.fY * scale); #endif } int winding = 1; if (y0 > y1) { SkTSwap(x0, x1); SkTSwap(y0, y1); winding = -1; } int top = SkFDot6Round(y0); int bot = SkFDot6Round(y1); // are we a zero-height line? if (top == bot) { return 0; } // are we completely above or below the clip? if (clip && (top >= clip->fBottom || bot <= clip->fTop)) { return 0; } SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0); const SkFDot6 dy = SkEdge_Compute_DY(top, y0); fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy)); // + SK_Fixed1/2 fDX = slope; fFirstY = top; fLastY = bot - 1; fCurveCount = 0; fWinding = SkToS8(winding); fCurveShift = 0; if (clip) { this->chopLineWithClip(*clip); } return 1; }
int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, int shift) { SkFDot6 x0, y0, x1, y1; { #ifdef SK_SCALAR_IS_FLOAT float scale = float(1 << (shift + 6)); x0 = int(p0.fX * scale); y0 = int(p0.fY * scale); x1 = int(p1.fX * scale); y1 = int(p1.fY * scale); #else shift = 10 - shift; x0 = p0.fX >> shift; y0 = p0.fY >> shift; x1 = p1.fX >> shift; y1 = p1.fY >> shift; #endif } int winding = 1; if (y0 > y1) { SkTSwap(x0, x1); SkTSwap(y0, y1); winding = -1; } int top = SkFDot6Round(y0); int bot = SkFDot6Round(y1); // are we a zero-height line? if (top == bot) { return 0; } // are we completely above or below the clip? if (NULL != clip && (top >= clip->fBottom || bot <= clip->fTop)) { return 0; } SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0); fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63)); // + SK_Fixed1/2 fDX = slope; fFirstY = top; fLastY = bot - 1; fCurveCount = 0; fWinding = SkToS8(winding); fCurveShift = 0; if (clip) { this->chopLineWithClip(*clip); } return 1; }
static void* draw_proc(void* context) { const int OVALW = 32; const int OVALH = 32; const SkBitmap* bm = static_cast<const SkBitmap*>(context); SkFlipPixelRef* ref = static_cast<SkFlipPixelRef*>(bm->pixelRef()); const int DSCALE = 1; SkScalar dx = SkIntToScalar(7) / DSCALE; SkScalar dy = SkIntToScalar(5) / DSCALE; SkScalar x = 0; SkScalar y = 0; SkPaint paint; paint.setAntiAlias(true); paint.setColor(SK_ColorRED); SkRect oval; oval.setEmpty(); while (!gDone) { ref->inval(oval, true); oval.set(x, y, x + SkIntToScalar(OVALW), y + SkIntToScalar(OVALH)); ref->inval(oval, true); SkAutoFlipUpdate update(ref); if (!update.dirty().isEmpty()) { // this must be local to the loop, since it needs to forget the pixels // its writing to after each iteration, since we do the swap SkCanvas canvas(update.bitmap()); // SkDebugf("----- dirty [%d %d %d %d]\n", dirty.getBounds().fLeft, dirty.getBounds().fTop, dirty.getBounds().width(), dirty.getBounds().height()); canvas.clipRegion(update.dirty()); canvas.drawColor(0, SkXfermode::kClear_Mode); canvas.drawOval(oval, paint); } bounce(&x, &dx, WIDTH-OVALW); bounce(&y, &dy, HEIGHT-OVALH); #if 1 for (int i = 0; i < 1000; i++) { for (int j = 0; j < 10000; j++) { SkFixedMul(j, 10); } } #endif } return NULL; }
void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* drawContext, GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { SkASSERT(byteLength == 0 || text != NULL); if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { return; } // This is the slow path, mainly used by Skia unit tests. The other // backends (8888, gpu, ...) use device-space dependent glyph caches. In // order to match the glyph positions that the other code paths produce, we // must also use device-space dependent glyph cache. This has the // side-effect that the glyph shape outline will be in device-space, // too. This in turn has the side-effect that NVPR can not stroke the paths, // as the stroke in NVPR is defined in object-space. // NOTE: here we have following coincidence that works at the moment: // - When using the device-space glyphs, the transforms we pass to NVPR // instanced drawing are the global transforms, and the view transform is // identity. NVPR can not use non-affine transforms in the instanced // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it // will turn off the use of device-space glyphs when perspective transforms // are in use. this->init(rt, clip, paint, skPaint, byteLength, kMaxAccuracy_RenderMode, viewMatrix, regionClipBounds); // Transform our starting point. if (fUsingDeviceSpaceGlyphs) { SkPoint loc; fContextInitialMatrix.mapXY(x, y, &loc); x = loc.fX; y = loc.fY; } SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); const char* stop = text + byteLength; // Measure first if needed. if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { SkFixed stopX = 0; SkFixed stopY = 0; const char* textPtr = text; while (textPtr < stop) { // We don't need x, y here, since all subpixel variants will have the // same advance. const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0); stopX += glyph.fAdvanceX; stopY += glyph.fAdvanceY; } SkASSERT(textPtr == stop); SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { alignX = SkScalarHalf(alignX); alignY = SkScalarHalf(alignY); } x -= alignX; y -= alignY; } SkAutoKern autokern; SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); SkFixed fx = SkScalarToFixed(x); SkFixed fy = SkScalarToFixed(y); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); if (glyph.fWidth) { this->appendGlyph(drawContext, glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy))); } fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); } this->finish(drawContext); }
void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { SkASSERT(byteLength == 0 || text != NULL); // nothing to draw if (text == NULL || byteLength == 0) { return; } fViewMatrix = viewMatrix; SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(skPaint, &fDeviceProperties, NULL); SkGlyphCache* cache = autoCache.getCache(); SkTArray<SkScalar> positions; const char* textPtr = text; SkFixed stopX = 0; SkFixed stopY = 0; SkFixed origin; switch (skPaint.getTextAlign()) { case SkPaint::kRight_Align: origin = SK_Fixed1; break; case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; case SkPaint::kLeft_Align: origin = 0; break; default: SkFAIL("Invalid paint origin"); return; } SkAutoKern autokern; const char* stop = text + byteLength; while (textPtr < stop) { // don't need x, y here, since all subpixel variants will have the // same advance const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0); SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); SkFixed height = glyph.fAdvanceY; positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))); stopX += width; stopY += height; } SkASSERT(textPtr == stop); // now adjust starting point depending on alignment SkScalar alignX = SkFixedToScalar(stopX); SkScalar alignY = SkFixedToScalar(stopY); if (skPaint.getTextAlign() == SkPaint::kCenter_Align) { alignX = SkScalarHalf(alignX); alignY = SkScalarHalf(alignY); } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { alignX = 0; alignY = 0; } x -= alignX; y -= alignY; SkPoint offset = SkPoint::Make(x, y); this->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, positions.begin(), 2, offset, regionClipBounds); }
void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != nullptr); SkGlyphCache* glyphCache = this->getGlyphCache(); SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); fTotalGlyphCount = fFont.countText(text, byteLength); fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType, fTotalGlyphCount)); const char* stop = text + byteLength; // Measure first if needed. if (fFont.getTextAlign() != SkPaint::kLeft_Align) { SkFixed stopX = 0; SkFixed stopY = 0; const char* textPtr = text; while (textPtr < stop) { // We don't need x, y here, since all subpixel variants will have the // same advance. const SkGlyph& glyph = glyphCacheProc(glyphCache, &textPtr, 0, 0); stopX += glyph.fAdvanceX; stopY += glyph.fAdvanceY; } SkASSERT(textPtr == stop); SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; if (fFont.getTextAlign() == SkPaint::kCenter_Align) { alignX = SkScalarHalf(alignX); alignY = SkScalarHalf(alignY); } x -= alignX; y -= alignY; } SkAutoKern autokern; SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); SkFixed fx = SkScalarToFixed(x); SkFixed fy = SkScalarToFixed(y); FallbackBlobBuilder fallback; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); if (glyph.fWidth) { this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)), &fallback); } fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); } fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount)); }
void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex, GrBatchFontCache* fontCache, const SkSurfaceProps& props, const SkPaint& skPaint, GrColor color, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != nullptr); // nothing to draw if (text == nullptr || byteLength == 0) { return; } SkPaint::GlyphCacheProc glyphCacheProc = skPaint.getGlyphCacheProc(true); SkAutoDescriptor desc; skPaint.getScalerContextDescriptor(&desc, props, SkPaint::FakeGamma::Off, nullptr); SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface(), desc.getDesc()); SkTArray<SkScalar> positions; const char* textPtr = text; SkFixed stopX = 0; SkFixed stopY = 0; SkFixed origin = 0; switch (skPaint.getTextAlign()) { case SkPaint::kRight_Align: origin = SK_Fixed1; break; case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; case SkPaint::kLeft_Align: origin = 0; break; } SkAutoKern autokern; const char* stop = text + byteLength; while (textPtr < stop) { // don't need x, y here, since all subpixel variants will have the // same advance const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr); SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); SkFixed height = glyph.fAdvanceY; positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))); stopX += width; stopY += height; } SkASSERT(textPtr == stop); SkGlyphCache::AttachCache(origPaintCache); // now adjust starting point depending on alignment SkScalar alignX = SkFixedToScalar(stopX); SkScalar alignY = SkFixedToScalar(stopY); if (skPaint.getTextAlign() == SkPaint::kCenter_Align) { alignX = SkScalarHalf(alignX); alignY = SkScalarHalf(alignY); } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { alignX = 0; alignY = 0; } x -= alignX; y -= alignY; SkPoint offset = SkPoint::Make(x, y); DrawDFPosText(blob, runIndex, fontCache, props, skPaint, color, viewMatrix, text, byteLength, positions.begin(), 2, offset); }
void SkGraphics::Init() { SkGlobals::Init(); #ifdef BUILD_EMBOSS_TABLE SkEmbossMask_BuildTable(); #endif #ifdef BUILD_RADIALGRADIENT_TABLE SkRadialGradient_BuildTable(); #endif #ifdef SK_DEBUGx int i; static const struct { const char* fTypeName; size_t fSizeOf; } gTypeSize[] = { typesizeline(char), typesizeline(short), typesizeline(int), typesizeline(long), typesizeline(size_t), typesizeline(void*), typesizeline(S8CPU), typesizeline(U8CPU), typesizeline(S16CPU), typesizeline(U16CPU), typesizeline(SkPoint), typesizeline(SkRect), typesizeline(SkMatrix), typesizeline(SkPath), typesizeline(SkGlyph), typesizeline(SkRefCnt), typesizeline(SkPaint), typesizeline(SkCanvas), typesizeline(SkBlitter), typesizeline(SkShader), typesizeline(SkXfermode), typesizeline(SkPathEffect) }; #ifdef SK_CPU_BENDIAN SkDebugf("SkGraphics: big-endian\n"); #else SkDebugf("SkGraphics: little-endian\n"); #endif { char test = 0xFF; int itest = test; // promote to int, see if it sign-extended if (itest < 0) SkDebugf("SkGraphics: char is signed\n"); else SkDebugf("SkGraphics: char is unsigned\n"); } for (i = 0; i < (int)SK_ARRAY_COUNT(gTypeSize); i++) { SkDebugf("SkGraphics: sizeof(%s) = %d\n", gTypeSize[i].fTypeName, gTypeSize[i].fSizeOf); } #endif if (false) // test asm fixmul { int j; SkMSec now = SkTime::GetMSecs(); for (j = 0; j < BIG_LOOP_COUNT; j++) { (void)SkFixedMul_portable(0x8000, 0x150000); } SkMSec now2 = SkTime::GetMSecs(); printf("-------- SkFixedMul_portable = %d\n", now2 - now); for (j = 0; j < BIG_LOOP_COUNT; j++) { (void)SkFixedMul(0x8000, 0x150000); } printf("-------- SkFixedMul = %d\n", SkTime::GetMSecs() - now2); SkRandom rand; for (j = 0; j < 10000; j++) { SkFixed a = rand.nextS() >> 8; SkFixed b = rand.nextS() >> 8; SkFixed c1 = SkFixedMul_portable(a, b); SkFixed c2 = SkFixedMul(a, b); if (SkAbs32(c1 - c2) > 1) printf("------ FixMul disagreement: (%x %x) slow=%x fast=%x\n", a, b, c1, c2); } }