ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { ShadowText entry(paint, radius, len, text, positions); ShadowTexture* texture = mCache.get(entry); if (!texture) { SkPaint paintCopy(*paint); paintCopy.setTextAlign(SkPaint::kLeft_Align); FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, text, 0, len, numGlyphs, radius, positions); texture = new ShadowTexture; texture->left = shadow.penX; texture->top = shadow.penY; texture->width = shadow.width; texture->height = shadow.height; texture->generation = 0; texture->blend = true; const uint32_t size = shadow.width * shadow.height; texture->bitmapSize = size; // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { while (mSize + size > mMaxSize) { mCache.removeOldest(); } } glGenTextures(1, &texture->id); glBindTexture(GL_TEXTURE_2D, texture->id); // Textures are Alpha8 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); texture->setFilter(GL_LINEAR); texture->setWrap(GL_CLAMP_TO_EDGE); if (size < mMaxSize) { if (mDebugEnabled) { ALOGD("Shadow texture created, size = %d", texture->bitmapSize); } entry.copyTextLocally(); mSize += size; mCache.put(entry, texture); } else { texture->cleanup = true; } // Cleanup shadow delete[] shadow.image; } return texture; }
void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { uint32_t flags; SkDrawFilter* drawFilter = getDrawFilter(); if (drawFilter) { SkPaint paintCopy(paint); drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); flags = paintCopy.getFlags(); } else { flags = paint.getFlags(); } if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { // Same values used by Skia const float kStdStrikeThru_Offset = (-6.0f / 21.0f); const float kStdUnderline_Offset = (1.0f / 9.0f); const float kStdUnderline_Thickness = (1.0f / 18.0f); SkScalar left = x; SkScalar right = x + length; float textSize = paint.getTextSize(); float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); if (flags & SkPaint::kUnderlineText_Flag) { SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; drawRect(left, top, right, bottom, paint); } if (flags & SkPaint::kStrikeThruText_Flag) { SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; drawRect(left, top, right, bottom, paint); } } }
ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, float radius, const float* positions) { ShadowText entry(paint, radius, numGlyphs, glyphs, positions); ShadowTexture* texture = mCache.get(entry); if (!texture) { SkPaint paintCopy(*paint); paintCopy.setTextAlign(SkPaint::kLeft_Align); FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs, radius, positions); if (!shadow.image) { return nullptr; } Caches& caches = Caches::getInstance(); texture = new ShadowTexture(caches); texture->left = shadow.penX; texture->top = shadow.penY; texture->generation = 0; texture->blend = true; const uint32_t size = shadow.width * shadow.height; // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { while (mSize + size > mMaxSize) { LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(), "Failed to remove oldest from cache. mSize = %" PRIu32 ", mCache.size() = %zu", mSize, mCache.size()); } } // Textures are Alpha8 texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); texture->setFilter(GL_LINEAR); texture->setWrap(GL_CLAMP_TO_EDGE); if (size < mMaxSize) { if (mDebugEnabled) { ALOGD("Shadow texture created, size = %d", texture->bitmapSize); } entry.copyTextLocally(); mSize += texture->objectSize(); mCache.put(entry, texture); } else { texture->cleanup = true; } // Cleanup shadow free(shadow.image); } return texture; }
void SkBaseDevice::drawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { SkLatticeIter iter(lattice, dst); SkRect srcR, dstR; SkColor c; bool isFixedColor = false; const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType); while (iter.next(&srcR, &dstR, &isFixedColor, &c)) { if (isFixedColor || (srcR.width() <= 1.0f && srcR.height() <= 1.0f && image->readPixels(info, &c, 4, srcR.fLeft, srcR.fTop))) { // Fast draw with drawRect, if this is a patch containing a single color // or if this is a patch containing a single pixel. if (0 != c || !paint.isSrcOver()) { SkPaint paintCopy(paint); int alpha = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha())); paintCopy.setColor(SkColorSetA(c, alpha)); this->drawRect(dstR, paintCopy); } } else { this->drawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); } } }
void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, float hOffset, float vOffset, const Paint& paint, Typeface* typeface) { Paint paintCopy(paint); Layout layout; MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count); hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); // Set align to left for drawing, as we don't want individual // glyphs centered or right-aligned; the offset above takes // care of all alignment. paintCopy.setTextAlign(Paint::kLeft_Align); DrawTextOnPathFunctor f(layout, this, hOffset, vOffset, paintCopy, path); MinikinUtils::forFontRun(layout, &paintCopy, f); }