summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/core/SkStrikeSpec.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/skia/skia/src/core/SkStrikeSpec.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkStrikeSpec.cpp b/gfx/skia/skia/src/core/SkStrikeSpec.cpp
new file mode 100644
index 0000000000..43a74eee0d
--- /dev/null
+++ b/gfx/skia/skia/src/core/SkStrikeSpec.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/core/SkStrikeSpec.h"
+
+#include "include/core/SkGraphics.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkPathEffect.h"
+#include "include/effects/SkDashPathEffect.h"
+#include "src/base/SkTLazy.h"
+#include "src/core/SkDraw.h"
+#include "src/core/SkFontPriv.h"
+#include "src/core/SkStrike.h"
+#include "src/core/SkStrikeCache.h"
+
+#if defined(SK_GANESH) || defined(SK_GRAPHITE)
+#include "src/text/gpu/SDFMaskFilter.h"
+#include "src/text/gpu/SDFTControl.h"
+#include "src/text/gpu/StrikeCache.h"
+#endif
+
+SkStrikeSpec::SkStrikeSpec(const SkDescriptor& descriptor, sk_sp<SkTypeface> typeface)
+ : fAutoDescriptor{descriptor}
+ , fTypeface{std::move(typeface)} {}
+
+SkStrikeSpec::SkStrikeSpec(const SkStrikeSpec&) = default;
+SkStrikeSpec::SkStrikeSpec(SkStrikeSpec&&) = default;
+SkStrikeSpec::~SkStrikeSpec() = default;
+
+SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint,
+ const SkSurfaceProps& surfaceProps,
+ SkScalerContextFlags scalerContextFlags,
+ const SkMatrix& deviceMatrix) {
+
+ return SkStrikeSpec(font, paint, surfaceProps, scalerContextFlags, deviceMatrix);
+}
+
+SkStrikeSpec SkStrikeSpec::MakeTransformMask(const SkFont& font,
+ const SkPaint& paint,
+ const SkSurfaceProps& surfaceProps,
+ SkScalerContextFlags scalerContextFlags,
+ const SkMatrix& deviceMatrix) {
+ SkFont sourceFont{font};
+ sourceFont.setSubpixel(false);
+ return SkStrikeSpec(sourceFont, paint, surfaceProps, scalerContextFlags, deviceMatrix);
+}
+
+std::tuple<SkStrikeSpec, SkScalar> SkStrikeSpec::MakePath(
+ const SkFont& font, const SkPaint& paint,
+ const SkSurfaceProps& surfaceProps,
+ SkScalerContextFlags scalerContextFlags) {
+
+ // setup our std runPaint, in hopes of getting hits in the cache
+ SkPaint pathPaint{paint};
+ SkFont pathFont{font};
+
+ // The sub-pixel position will always happen when transforming to the screen.
+ pathFont.setSubpixel(false);
+
+ // The factor to get from the size stored in the strike to the size needed for
+ // the source.
+ SkScalar strikeToSourceScale = pathFont.setupForAsPaths(&pathPaint);
+
+ return {SkStrikeSpec(pathFont, pathPaint, surfaceProps, scalerContextFlags, SkMatrix::I()),
+ strikeToSourceScale};
+}
+
+std::tuple<SkStrikeSpec, SkScalar> SkStrikeSpec::MakeCanonicalized(
+ const SkFont& font, const SkPaint* paint) {
+ SkPaint canonicalizedPaint;
+ if (paint != nullptr) {
+ canonicalizedPaint = *paint;
+ }
+
+ const SkFont* canonicalizedFont = &font;
+ SkTLazy<SkFont> pathFont;
+ SkScalar strikeToSourceScale = 1;
+ if (ShouldDrawAsPath(canonicalizedPaint, font, SkMatrix::I())) {
+ canonicalizedFont = pathFont.set(font);
+ strikeToSourceScale = pathFont->setupForAsPaths(nullptr);
+ canonicalizedPaint.reset();
+ }
+
+ return {SkStrikeSpec(*canonicalizedFont, canonicalizedPaint, SkSurfaceProps(),
+ SkScalerContextFlags::kFakeGammaAndBoostContrast, SkMatrix::I()),
+ strikeToSourceScale};
+}
+
+SkStrikeSpec SkStrikeSpec::MakeWithNoDevice(const SkFont& font, const SkPaint* paint) {
+ SkPaint setupPaint;
+ if (paint != nullptr) {
+ setupPaint = *paint;
+ }
+
+ return SkStrikeSpec(font, setupPaint, SkSurfaceProps(),
+ SkScalerContextFlags::kFakeGammaAndBoostContrast, SkMatrix::I());
+}
+
+bool SkStrikeSpec::ShouldDrawAsPath(
+ const SkPaint& paint, const SkFont& font, const SkMatrix& viewMatrix) {
+
+ // hairline glyphs are fast enough, so we don't need to cache them
+ if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
+ return true;
+ }
+
+ // we don't cache perspective
+ if (viewMatrix.hasPerspective()) {
+ return true;
+ }
+
+ // Glyphs like Emojis can't be rendered as a path.
+ if (font.getTypeface() && font.getTypeface()->hasColorGlyphs()) {
+ return false;
+ }
+
+ SkMatrix textMatrix = SkFontPriv::MakeTextMatrix(font);
+ textMatrix.postConcat(viewMatrix);
+
+ // we have a self-imposed maximum, just to limit memory-usage
+ constexpr SkScalar memoryLimit = 256;
+ constexpr SkScalar maxSizeSquared = memoryLimit * memoryLimit;
+
+ auto distance = [&textMatrix](int XIndex, int YIndex) {
+ return textMatrix[XIndex] * textMatrix[XIndex] + textMatrix[YIndex] * textMatrix[YIndex];
+ };
+
+ return distance(SkMatrix::kMScaleX, SkMatrix::kMSkewY ) > maxSizeSquared
+ || distance(SkMatrix::kMSkewX, SkMatrix::kMScaleY) > maxSizeSquared;
+}
+
+SkString SkStrikeSpec::dump() const {
+ return fAutoDescriptor.getDesc()->dumpRec();
+}
+
+SkStrikeSpec SkStrikeSpec::MakePDFVector(const SkTypeface& typeface, int* size) {
+ SkFont font;
+ font.setHinting(SkFontHinting::kNone);
+ font.setEdging(SkFont::Edging::kAlias);
+ font.setTypeface(sk_ref_sp(&typeface));
+ int unitsPerEm = typeface.getUnitsPerEm();
+ if (unitsPerEm <= 0) {
+ unitsPerEm = 1024;
+ }
+ if (size) {
+ *size = unitsPerEm;
+ }
+ font.setSize((SkScalar)unitsPerEm);
+
+ return SkStrikeSpec(font,
+ SkPaint(),
+ SkSurfaceProps(0, kUnknown_SkPixelGeometry),
+ SkScalerContextFlags::kFakeGammaAndBoostContrast,
+ SkMatrix::I());
+}
+
+#if (defined(SK_GANESH) || defined(SK_GRAPHITE)) && !defined(SK_DISABLE_SDF_TEXT)
+std::tuple<SkStrikeSpec, SkScalar, sktext::gpu::SDFTMatrixRange>
+SkStrikeSpec::MakeSDFT(const SkFont& font, const SkPaint& paint,
+ const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix,
+ const SkPoint& textLocation, const sktext::gpu::SDFTControl& control) {
+ // Add filter to the paint which creates the SDFT data for A8 masks.
+ SkPaint dfPaint{paint};
+ dfPaint.setMaskFilter(sktext::gpu::SDFMaskFilter::Make());
+
+ auto [dfFont, strikeToSourceScale, matrixRange] = control.getSDFFont(font, deviceMatrix,
+ textLocation);
+
+ // Adjust the stroke width by the scale factor for drawing the SDFT.
+ dfPaint.setStrokeWidth(paint.getStrokeWidth() / strikeToSourceScale);
+
+ // Check for dashing and adjust the intervals.
+ if (SkPathEffect* pathEffect = paint.getPathEffect(); pathEffect != nullptr) {
+ SkPathEffect::DashInfo dashInfo;
+ if (pathEffect->asADash(&dashInfo) == SkPathEffect::kDash_DashType) {
+ if (dashInfo.fCount > 0) {
+ // Allocate the intervals.
+ std::vector<SkScalar> scaledIntervals(dashInfo.fCount);
+ dashInfo.fIntervals = scaledIntervals.data();
+ // Call again to get the interval data.
+ (void)pathEffect->asADash(&dashInfo);
+ for (SkScalar& interval : scaledIntervals) {
+ interval /= strikeToSourceScale;
+ }
+ auto scaledDashes = SkDashPathEffect::Make(scaledIntervals.data(),
+ scaledIntervals.size(),
+ dashInfo.fPhase / strikeToSourceScale);
+ dfPaint.setPathEffect(scaledDashes);
+ }
+ }
+ }
+
+ // Fake-gamma and subpixel antialiasing are applied in the shader, so we ignore the
+ // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
+ SkScalerContextFlags flags = SkScalerContextFlags::kNone;
+ SkStrikeSpec strikeSpec(dfFont, dfPaint, surfaceProps, flags, SkMatrix::I());
+
+ return std::make_tuple(std::move(strikeSpec), strikeToSourceScale, matrixRange);
+}
+#endif
+
+SkStrikeSpec::SkStrikeSpec(const SkFont& font, const SkPaint& paint,
+ const SkSurfaceProps& surfaceProps,
+ SkScalerContextFlags scalerContextFlags,
+ const SkMatrix& deviceMatrix) {
+ SkScalerContextEffects effects;
+
+ SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
+ font, paint, surfaceProps, scalerContextFlags, deviceMatrix,
+ &fAutoDescriptor, &effects);
+
+ fMaskFilter = sk_ref_sp(effects.fMaskFilter);
+ fPathEffect = sk_ref_sp(effects.fPathEffect);
+ fTypeface = font.refTypefaceOrDefault();
+}
+
+sk_sp<sktext::StrikeForGPU> SkStrikeSpec::findOrCreateScopedStrike(
+ sktext::StrikeForGPUCacheInterface* cache) const {
+ return cache->findOrCreateScopedStrike(*this);
+}
+
+sk_sp<SkStrike> SkStrikeSpec::findOrCreateStrike() const {
+ SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
+ return SkStrikeCache::GlobalStrikeCache()->findOrCreateStrike(*this);
+}
+
+sk_sp<SkStrike> SkStrikeSpec::findOrCreateStrike(SkStrikeCache* cache) const {
+ SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
+ return cache->findOrCreateStrike(*this);
+}
+
+SkBulkGlyphMetrics::SkBulkGlyphMetrics(const SkStrikeSpec& spec)
+ : fStrike{spec.findOrCreateStrike()} { }
+
+SkSpan<const SkGlyph*> SkBulkGlyphMetrics::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
+ fGlyphs.reset(glyphIDs.size());
+ return fStrike->metrics(glyphIDs, fGlyphs.get());
+}
+
+const SkGlyph* SkBulkGlyphMetrics::glyph(SkGlyphID glyphID) {
+ return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
+}
+
+SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec)
+ : fStrike{spec.findOrCreateStrike()} { }
+
+SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(sk_sp<SkStrike>&& strike)
+ : fStrike{std::move(strike)} { }
+
+SkBulkGlyphMetricsAndPaths::~SkBulkGlyphMetricsAndPaths() = default;
+
+SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndPaths::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
+ fGlyphs.reset(glyphIDs.size());
+ return fStrike->preparePaths(glyphIDs, fGlyphs.get());
+}
+
+const SkGlyph* SkBulkGlyphMetricsAndPaths::glyph(SkGlyphID glyphID) {
+ return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
+}
+
+void SkBulkGlyphMetricsAndPaths::findIntercepts(
+ const SkScalar* bounds, SkScalar scale, SkScalar xPos,
+ const SkGlyph* glyph, SkScalar* array, int* count) {
+ // TODO(herb): remove this abominable const_cast. Do the intercepts really need to be on the
+ // glyph?
+ fStrike->findIntercepts(bounds, scale, xPos, const_cast<SkGlyph*>(glyph), array, count);
+}
+
+SkBulkGlyphMetricsAndDrawables::SkBulkGlyphMetricsAndDrawables(const SkStrikeSpec& spec)
+ : fStrike{spec.findOrCreateStrike()} { }
+
+SkBulkGlyphMetricsAndDrawables::SkBulkGlyphMetricsAndDrawables(sk_sp<SkStrike>&& strike)
+ : fStrike{std::move(strike)} { }
+
+SkBulkGlyphMetricsAndDrawables::~SkBulkGlyphMetricsAndDrawables() = default;
+
+SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndDrawables::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
+ fGlyphs.reset(glyphIDs.size());
+ return fStrike->prepareDrawables(glyphIDs, fGlyphs.get());
+}
+
+const SkGlyph* SkBulkGlyphMetricsAndDrawables::glyph(SkGlyphID glyphID) {
+ return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
+}
+
+SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec)
+ : fStrike{spec.findOrCreateStrike()} { }
+
+SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(sk_sp<SkStrike>&& strike)
+ : fStrike{std::move(strike)} { }
+
+SkBulkGlyphMetricsAndImages::~SkBulkGlyphMetricsAndImages() = default;
+
+SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndImages::glyphs(SkSpan<const SkPackedGlyphID> glyphIDs) {
+ fGlyphs.reset(glyphIDs.size());
+ return fStrike->prepareImages(glyphIDs, fGlyphs.get());
+}
+
+const SkGlyph* SkBulkGlyphMetricsAndImages::glyph(SkPackedGlyphID packedID) {
+ return this->glyphs(SkSpan<const SkPackedGlyphID>{&packedID, 1})[0];
+}
+
+const SkDescriptor& SkBulkGlyphMetricsAndImages::descriptor() const {
+ return fStrike->getDescriptor();
+}