SkGlyphRunPainter.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. /*
  2. * Copyright 2018 The Android Open Source Project
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/core/SkGlyphRunPainter.h"
  8. #if SK_SUPPORT_GPU
  9. #include "include/private/GrRecordingContext.h"
  10. #include "src/gpu/GrCaps.h"
  11. #include "src/gpu/GrColorSpaceInfo.h"
  12. #include "src/gpu/GrContextPriv.h"
  13. #include "src/gpu/GrRecordingContextPriv.h"
  14. #include "src/gpu/GrRenderTargetContext.h"
  15. #include "src/gpu/SkGr.h"
  16. #include "src/gpu/text/GrTextBlobCache.h"
  17. #include "src/gpu/text/GrTextContext.h"
  18. #endif
  19. #include "include/core/SkColorFilter.h"
  20. #include "include/core/SkMaskFilter.h"
  21. #include "include/core/SkPathEffect.h"
  22. #include "include/private/SkTDArray.h"
  23. #include "src/core/SkDevice.h"
  24. #include "src/core/SkDistanceFieldGen.h"
  25. #include "src/core/SkDraw.h"
  26. #include "src/core/SkFontPriv.h"
  27. #include "src/core/SkPaintPriv.h"
  28. #include "src/core/SkRasterClip.h"
  29. #include "src/core/SkRemoteGlyphCacheImpl.h"
  30. #include "src/core/SkStrike.h"
  31. #include "src/core/SkStrikeCache.h"
  32. #include "src/core/SkStrikeInterface.h"
  33. #include "src/core/SkStrikeSpec.h"
  34. #include "src/core/SkTraceEvent.h"
  35. #include <limits.h>
  36. // -- SkGlyphCacheCommon ---------------------------------------------------------------------------
  37. SkVector SkStrikeCommon::PixelRounding(bool isSubpixel, SkAxisAlignment axisAlignment) {
  38. if (!isSubpixel) {
  39. return {SK_ScalarHalf, SK_ScalarHalf};
  40. } else {
  41. static constexpr SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRound);
  42. switch (axisAlignment) {
  43. case kX_SkAxisAlignment:
  44. return {kSubpixelRounding, SK_ScalarHalf};
  45. case kY_SkAxisAlignment:
  46. return {SK_ScalarHalf, kSubpixelRounding};
  47. case kNone_SkAxisAlignment:
  48. return {kSubpixelRounding, kSubpixelRounding};
  49. }
  50. }
  51. // Some compilers need this.
  52. return {0, 0};
  53. }
  54. // -- SkGlyphRunListPainter ------------------------------------------------------------------------
  55. SkGlyphRunListPainter::SkGlyphRunListPainter(const SkSurfaceProps& props,
  56. SkColorType colorType,
  57. SkScalerContextFlags flags,
  58. SkStrikeCacheInterface* strikeCache)
  59. : fDeviceProps{props}
  60. , fBitmapFallbackProps{SkSurfaceProps{props.flags(), kUnknown_SkPixelGeometry}}
  61. , fColorType{colorType}, fScalerContextFlags{flags}
  62. , fStrikeCache{strikeCache} {}
  63. // TODO: unify with code in GrTextContext.cpp
  64. static SkScalerContextFlags compute_scaler_context_flags(const SkColorSpace* cs) {
  65. // If we're doing linear blending, then we can disable the gamma hacks.
  66. // Otherwise, leave them on. In either case, we still want the contrast boost:
  67. // TODO: Can we be even smarter about mask gamma based on the dest transfer function?
  68. if (cs && cs->gammaIsLinear()) {
  69. return SkScalerContextFlags::kBoostContrast;
  70. } else {
  71. return SkScalerContextFlags::kFakeGammaAndBoostContrast;
  72. }
  73. }
  74. SkGlyphRunListPainter::SkGlyphRunListPainter(const SkSurfaceProps& props,
  75. SkColorType colorType,
  76. SkColorSpace* cs,
  77. SkStrikeCacheInterface* strikeCache)
  78. : SkGlyphRunListPainter(props, colorType, compute_scaler_context_flags(cs), strikeCache) {}
  79. #if SK_SUPPORT_GPU
  80. SkGlyphRunListPainter::SkGlyphRunListPainter(const SkSurfaceProps& props,
  81. const GrColorSpaceInfo& csi)
  82. : SkGlyphRunListPainter(props,
  83. kUnknown_SkColorType,
  84. compute_scaler_context_flags(csi.colorSpace()),
  85. SkStrikeCache::GlobalStrikeCache()) {}
  86. SkGlyphRunListPainter::SkGlyphRunListPainter(const GrRenderTargetContext& rtc)
  87. : SkGlyphRunListPainter{rtc.surfaceProps(), rtc.colorSpaceInfo()} {}
  88. #endif
  89. static bool check_glyph_position(SkPoint position) {
  90. // Prevent glyphs from being drawn outside of or straddling the edge of device space.
  91. // Comparisons written a little weirdly so that NaN coordinates are treated safely.
  92. auto gt = [](float a, int b) { return !(a <= (float)b); };
  93. auto lt = [](float a, int b) { return !(a >= (float)b); };
  94. return !(gt(position.fX, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) ||
  95. lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) ||
  96. gt(position.fY, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) ||
  97. lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)));
  98. }
  99. SkSpan<const SkPackedGlyphID> SkGlyphRunListPainter::DeviceSpacePackedGlyphIDs(
  100. SkStrikeInterface* strike,
  101. const SkMatrix& viewMatrix,
  102. const SkPoint& origin,
  103. int n,
  104. const SkGlyphID* glyphIDs,
  105. const SkPoint* positions,
  106. SkPoint* mappedPositions,
  107. SkPackedGlyphID* results) {
  108. // Add rounding and origin.
  109. SkMatrix matrix = viewMatrix;
  110. matrix.preTranslate(origin.x(), origin.y());
  111. SkPoint rounding = strike->rounding();
  112. matrix.postTranslate(rounding.x(), rounding.y());
  113. matrix.mapPoints(mappedPositions, positions, n);
  114. SkIPoint mask = strike->subpixelMask();
  115. for (int i = 0; i < n; i++) {
  116. SkFixed subX = SkScalarToFixed(mappedPositions[i].x()) & mask.x(),
  117. subY = SkScalarToFixed(mappedPositions[i].y()) & mask.y();
  118. results[i] = SkPackedGlyphID{glyphIDs[i], subX, subY};
  119. }
  120. return SkSpan<const SkPackedGlyphID>{results, SkTo<size_t>(n)};
  121. }
  122. SkSpan<const SkPackedGlyphID> SkGlyphRunListPainter::SourceSpacePackedGlyphIDs(
  123. const SkPoint& origin,
  124. int n,
  125. const SkGlyphID* glyphIDs,
  126. const SkPoint* positions,
  127. SkPoint* mappedPositions,
  128. SkPackedGlyphID* results) {
  129. SkMatrix::MakeTrans(origin.x(), origin.y()).mapPoints(
  130. mappedPositions, positions, n);
  131. SkPackedGlyphID* cursor = results;
  132. for (int i = 0; i < n; i++) {
  133. *cursor++ = SkPackedGlyphID{glyphIDs[i]};
  134. }
  135. return SkSpan<const SkPackedGlyphID>{results, SkTo<size_t>(n)};
  136. }
  137. void SkGlyphRunListPainter::drawForBitmapDevice(
  138. const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
  139. const BitmapDevicePainter* bitmapDevice) {
  140. ScopedBuffers _ = this->ensureBuffers(glyphRunList);
  141. const SkPaint& runPaint = glyphRunList.paint();
  142. // The bitmap blitters can only draw lcd text to a N32 bitmap in srcOver. Otherwise,
  143. // convert the lcd text into A8 text. The props communicates this to the scaler.
  144. auto& props = (kN32_SkColorType == fColorType && runPaint.isSrcOver())
  145. ? fDeviceProps
  146. : fBitmapFallbackProps;
  147. SkPoint origin = glyphRunList.origin();
  148. for (auto& glyphRun : glyphRunList) {
  149. const SkFont& runFont = glyphRun.font();
  150. auto runSize = glyphRun.runSize();
  151. if (SkStrikeSpec::ShouldDrawAsPath(runPaint, runFont, deviceMatrix)) {
  152. SkStrikeSpec strikeSpec = SkStrikeSpec::MakePath(
  153. runFont, runPaint, props, fScalerContextFlags);
  154. auto strike = strikeSpec.findOrCreateExclusiveStrike();
  155. auto packedGlyphIDs = SourceSpacePackedGlyphIDs(
  156. origin,
  157. runSize,
  158. glyphRun.glyphsIDs().data(),
  159. glyphRun.positions().data(),
  160. fPositions,
  161. fPackedGlyphIDs);
  162. auto glyphPosSpan = strike->prepareForDrawing(packedGlyphIDs.data(),
  163. fPositions,
  164. glyphRun.runSize(),
  165. 0,
  166. SkStrikeInterface::kBoundsOnly,
  167. fGlyphPos);
  168. SkTDArray<SkPathPos> pathsAndPositions;
  169. pathsAndPositions.setReserve(glyphPosSpan.size());
  170. for (const SkGlyphPos& glyphPos : glyphPosSpan) {
  171. const SkGlyph& glyph = *glyphPos.glyph;
  172. SkPoint position = glyphPos.position;
  173. if (check_glyph_position(position)
  174. && !glyph.isEmpty()
  175. && !glyph.isColor()
  176. && glyph.path() != nullptr)
  177. {
  178. // Only draw a path if it exists, and this is not a color glyph.
  179. pathsAndPositions.push_back(SkPathPos{glyph.path(), position});
  180. } else {
  181. // TODO: this is here to have chrome layout tests pass. Remove this when
  182. // fallback for CPU works.
  183. const SkPath* path = strike->preparePath((SkGlyph*) &glyph);
  184. if (check_glyph_position(position) && !glyph.isEmpty() && path != nullptr) {
  185. pathsAndPositions.push_back(SkPathPos{path, position});
  186. }
  187. }
  188. }
  189. // The paint we draw paths with must have the same anti-aliasing state as the runFont
  190. // allowing the paths to have the same edging as the glyph masks.
  191. SkPaint pathPaint = runPaint;
  192. pathPaint.setAntiAlias(runFont.hasSomeAntiAliasing());
  193. bitmapDevice->paintPaths(
  194. SkSpan<const SkPathPos>{pathsAndPositions.begin(), pathsAndPositions.size()},
  195. strikeSpec.strikeToSourceRatio(), pathPaint);
  196. } else {
  197. SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(
  198. runFont, runPaint, props, fScalerContextFlags, deviceMatrix);
  199. auto strike = strikeSpec.findOrCreateExclusiveStrike();
  200. auto packedGlyphIDs = DeviceSpacePackedGlyphIDs(
  201. strike.get(),
  202. deviceMatrix,
  203. origin,
  204. runSize,
  205. glyphRun.glyphsIDs().data(),
  206. glyphRun.positions().data(),
  207. fPositions,
  208. fPackedGlyphIDs);
  209. SkSpan<const SkGlyphPos> glyphPosSpan = strike->prepareForDrawing(
  210. packedGlyphIDs.data(),
  211. fPositions,
  212. glyphRun.runSize(),
  213. std::numeric_limits<int>::max(),
  214. SkStrikeInterface::kImageIfNeeded,
  215. fGlyphPos);
  216. SkTDArray<SkMask> masks;
  217. masks.setReserve(glyphPosSpan.size());
  218. for (const SkGlyphPos& glyphPos : glyphPosSpan) {
  219. const SkGlyph& glyph = *glyphPos.glyph;
  220. SkPoint position = glyphPos.position;
  221. // The glyph could have dimensions (!isEmpty()), but still may have no bits if
  222. // the width is too wide. So check that there really is an image.
  223. if (check_glyph_position(position) && glyph.image() != nullptr) {
  224. masks.push_back(glyph.mask(position));
  225. }
  226. }
  227. bitmapDevice->paintMasks(SkSpan<const SkMask>{masks.begin(), masks.size()}, runPaint);
  228. }
  229. }
  230. }
  231. // Getting glyphs to the screen in a fallback situation can be complex. Here is the set of
  232. // transformations that have to happen. Normally, they would all be accommodated by the font
  233. // scaler, but the atlas has an upper limit to the glyphs it can handle. So the GPU is used to
  234. // make up the difference from the smaller atlas size to the larger size needed by the final
  235. // transform. Here are the transformations that are applied.
  236. //
  237. // final transform = [view matrix] * [text scale] * [text size]
  238. //
  239. // There are three cases:
  240. // * Go Fast - view matrix is scale and translate, and all the glyphs are small enough
  241. // Just scale the positions, and have the glyph cache handle the view matrix transformation.
  242. // The text scale is 1.
  243. // * It's complicated - view matrix is not scale and translate, and the glyphs are small enough
  244. // The glyph cache does not handle the view matrix, but stores the glyphs at the text size
  245. // specified by the run paint. The GPU handles the rotation, etc. specified by the view matrix.
  246. // The text scale is 1.
  247. // * Too big - The glyphs are too big to fit in the atlas
  248. // Reduce the text size so the glyphs will fit in the atlas, but don't apply any
  249. // transformations from the view matrix. Calculate a text scale based on that reduction. This
  250. // scale factor is used to increase the size of the destination rectangles. The destination
  251. // rectangles are then scaled, rotated, etc. by the GPU using the view matrix.
  252. void SkGlyphRunListPainter::processARGBFallback(SkScalar maxSourceGlyphDimension,
  253. const SkPaint& runPaint,
  254. const SkFont& runFont,
  255. const SkMatrix& viewMatrix,
  256. SkGlyphRunPainterInterface* process) {
  257. SkASSERT(!fARGBGlyphsIDs.empty());
  258. // if maxSourceGlyphDimension then no pixels will change.
  259. if (maxSourceGlyphDimension == 0) { return; }
  260. SkScalar maxScale = viewMatrix.getMaxScale();
  261. // This is a linear estimate of the longest dimension among all the glyph widths and heights.
  262. SkScalar conservativeMaxGlyphDimension = maxSourceGlyphDimension * maxScale;
  263. // If the situation that the matrix is simple, and all the glyphs are small enough. Go fast!
  264. // N.B. If the matrix has scale, that will be reflected in the strike through the viewMatrix
  265. // in the useFastPath case.
  266. bool useDeviceCache =
  267. viewMatrix.isScaleTranslate()
  268. && conservativeMaxGlyphDimension <= SkStrikeCommon::kSkSideTooBigForAtlas;
  269. // A scaled and translated transform is the common case, and is handled directly in fallback.
  270. // Even if the transform is scale and translate, fallback must be careful to use glyphs that
  271. // fit in the atlas. If a glyph will not fit in the atlas, then the general transform case is
  272. // used to render the glyphs.
  273. if (useDeviceCache) {
  274. // Translate the positions to device space.
  275. // TODO: this code is dubious
  276. viewMatrix.mapPoints(fARGBPositions.data(), fARGBPositions.size());
  277. for (SkPoint& point : fARGBPositions) {
  278. point.fX = SkScalarFloorToScalar(point.fX);
  279. point.fY = SkScalarFloorToScalar(point.fY);
  280. }
  281. SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(
  282. runFont, runPaint, fDeviceProps, fScalerContextFlags, viewMatrix);
  283. SkScopedStrike strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
  284. SkPackedGlyphID* cursor = fPackedGlyphIDs;
  285. for (auto glyphID : fARGBGlyphsIDs) {
  286. *cursor++ = SkPackedGlyphID{glyphID};
  287. }
  288. SkSpan<const SkGlyphPos> glyphPosSpan = strike->prepareForDrawing(
  289. fPackedGlyphIDs,
  290. fARGBPositions.data(),
  291. fARGBGlyphsIDs.size(),
  292. SkStrikeCommon::kSkSideTooBigForAtlas,
  293. SkStrikeInterface::kBoundsOnly,
  294. fGlyphPos);
  295. if (process) {
  296. process->processDeviceFallback(glyphPosSpan, strikeSpec);
  297. }
  298. } else {
  299. // If the matrix is complicated or if scaling is used to fit the glyphs in the cache,
  300. // then this case is used.
  301. SkStrikeSpec strikeSpec = SkStrikeSpec::MakeSourceFallback(
  302. runFont, runPaint, fDeviceProps, fScalerContextFlags, maxSourceGlyphDimension);
  303. SkScopedStrike strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
  304. SkPackedGlyphID* cursor = fPackedGlyphIDs;
  305. for (auto glyphID : fARGBGlyphsIDs) {
  306. *cursor++ = SkPackedGlyphID{glyphID};
  307. }
  308. auto glyphPosSpan = strike->prepareForDrawing(fPackedGlyphIDs,
  309. fARGBPositions.data(),
  310. fARGBGlyphsIDs.size(),
  311. SkStrikeCommon::kSkSideTooBigForAtlas,
  312. SkStrikeInterface::kBoundsOnly,
  313. fGlyphPos);
  314. if (process) {
  315. process->processSourceFallback(
  316. glyphPosSpan,
  317. strikeSpec,
  318. viewMatrix.hasPerspective());
  319. }
  320. }
  321. }
  322. #if SK_SUPPORT_GPU
  323. void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunList,
  324. const SkMatrix& viewMatrix,
  325. const SkSurfaceProps& props,
  326. bool contextSupportsDistanceFieldText,
  327. const GrTextContext::Options& options,
  328. SkGlyphRunPainterInterface* process) {
  329. SkPoint origin = glyphRunList.origin();
  330. const SkPaint& runPaint = glyphRunList.paint();
  331. for (const auto& glyphRun : glyphRunList) {
  332. SkScalar maxFallbackDimension{-SK_ScalarInfinity};
  333. ScopedBuffers _ = this->ensureBuffers(glyphRun);
  334. auto addFallback = [this, &maxFallbackDimension]
  335. (const SkGlyph& glyph, SkPoint sourcePosition) {
  336. maxFallbackDimension = std::max(maxFallbackDimension,
  337. SkIntToScalar(glyph.maxDimension()));
  338. fARGBGlyphsIDs.push_back(glyph.getGlyphID());
  339. fARGBPositions.push_back(sourcePosition);
  340. };
  341. const SkFont& runFont = glyphRun.font();
  342. bool useSDFT = GrTextContext::CanDrawAsDistanceFields(
  343. runPaint, runFont, viewMatrix, props, contextSupportsDistanceFieldText, options);
  344. if (process) {
  345. process->startRun(glyphRun, useSDFT);
  346. }
  347. if (useSDFT) {
  348. SkScalar minScale, maxScale;
  349. SkStrikeSpec strikeSpec;
  350. std::tie(strikeSpec, minScale, maxScale) =
  351. SkStrikeSpec::MakeSDFT(
  352. runFont, runPaint,fDeviceProps, viewMatrix, options);
  353. SkScopedStrike strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
  354. auto packedGlyphIDs = SourceSpacePackedGlyphIDs(
  355. origin,
  356. glyphRun.runSize(),
  357. glyphRun.glyphsIDs().data(),
  358. glyphRun.positions().data(),
  359. fPositions,
  360. fPackedGlyphIDs);
  361. SkSpan<const SkGlyphPos> glyphPosSpan = strike->prepareForDrawing(
  362. packedGlyphIDs.data(),
  363. fPositions,
  364. glyphRun.runSize(),
  365. SkStrikeCommon::kSkSideTooBigForAtlas,
  366. SkStrikeInterface::kBoundsOnly,
  367. fGlyphPos);
  368. size_t glyphsWithMaskCount = 0;
  369. for (const SkGlyphPos& glyphPos : glyphPosSpan) {
  370. const SkGlyph& glyph = *glyphPos.glyph;
  371. SkPoint position = glyphPos.position;
  372. // The SDF scaler context system ensures that a glyph is empty, kSDF_Format, or
  373. // kARGB32_Format. The following if statements use this assumption.
  374. SkASSERT(glyph.isEmpty()
  375. || glyph.maskFormat() == SkMask::kSDF_Format
  376. || glyph.isColor());
  377. if (glyph.isEmpty()) {
  378. // do nothing
  379. } else if (glyph.maskFormat() == SkMask::kSDF_Format
  380. && glyph.maxDimension() <= SkStrikeCommon::kSkSideTooBigForAtlas) {
  381. // SDF mask will work.
  382. fGlyphPos[glyphsWithMaskCount++] = glyphPos;
  383. } else if (!glyph.isColor()
  384. && glyph.path() != nullptr) {
  385. // If not color but too big, use a path.
  386. fPaths.push_back(glyphPos);
  387. } else {
  388. // If no path, or it is color, then fallback.
  389. addFallback(glyph, position);
  390. }
  391. }
  392. if (process) {
  393. bool hasWCoord =
  394. viewMatrix.hasPerspective() || options.fDistanceFieldVerticesAlwaysHaveW;
  395. // processSourceSDFT must be called even if there are no glyphs to make sure runs
  396. // are set correctly.
  397. process->processSourceSDFT(
  398. SkSpan<const SkGlyphPos>{fGlyphPos, glyphsWithMaskCount},
  399. strikeSpec,
  400. runFont,
  401. minScale,
  402. maxScale,
  403. hasWCoord);
  404. if (!fPaths.empty()) {
  405. process->processSourcePaths(
  406. SkMakeSpan(fPaths),
  407. strikeSpec);
  408. }
  409. }
  410. // fGlyphPos will be reused here.
  411. if (!fARGBGlyphsIDs.empty()) {
  412. this->processARGBFallback(maxFallbackDimension * strikeSpec.strikeToSourceRatio(),
  413. runPaint, runFont, viewMatrix, process);
  414. }
  415. } else if (SkStrikeSpec::ShouldDrawAsPath(runPaint, runFont, viewMatrix)) {
  416. SkStrikeSpec strikeSpec = SkStrikeSpec::MakePath(
  417. runFont, runPaint, fDeviceProps, fScalerContextFlags);
  418. SkScopedStrike strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
  419. auto packedGlyphIDs = SourceSpacePackedGlyphIDs(
  420. origin,
  421. glyphRun.runSize(),
  422. glyphRun.glyphsIDs().data(),
  423. glyphRun.positions().data(),
  424. fPositions,
  425. fPackedGlyphIDs);
  426. SkSpan<const SkGlyphPos> glyphPosSpan = strike->prepareForDrawing(
  427. packedGlyphIDs.data(),
  428. fPositions,
  429. glyphRun.runSize(),
  430. 0,
  431. SkStrikeInterface::kBoundsOnly,
  432. fGlyphPos);
  433. // As opposed to SDF and mask, path handling puts paths in fGlyphPos instead of fPaths.
  434. size_t glyphsWithPathCount = 0;
  435. for (const SkGlyphPos& glyphPos : glyphPosSpan) {
  436. const SkGlyph& glyph = *glyphPos.glyph;
  437. SkPoint position = glyphPos.position;
  438. if (glyph.isEmpty()) {
  439. // do nothing
  440. } else if (!glyph.isColor()
  441. && glyph.path() != nullptr) {
  442. // Place paths in fGlyphPos
  443. fGlyphPos[glyphsWithPathCount++] = glyphPos;
  444. } else {
  445. addFallback(glyph, position);
  446. }
  447. }
  448. if (process) {
  449. // processSourcePaths must be called even if there are no glyphs to make sure runs
  450. // are set correctly.
  451. process->processSourcePaths(
  452. SkSpan<const SkGlyphPos>{fGlyphPos, glyphsWithPathCount},
  453. strikeSpec);
  454. }
  455. // fGlyphPos will be reused here.
  456. if (!fARGBGlyphsIDs.empty()) {
  457. this->processARGBFallback(maxFallbackDimension * strikeSpec.strikeToSourceRatio(),
  458. runPaint, runFont, viewMatrix, process);
  459. }
  460. } else {
  461. SkStrikeSpec strikeSpec =
  462. SkStrikeSpec::MakeMask(runFont, runPaint,
  463. fDeviceProps, fScalerContextFlags, viewMatrix);
  464. SkScopedStrike strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
  465. auto packedGlyphIDs = DeviceSpacePackedGlyphIDs(
  466. strike.get(),
  467. viewMatrix,
  468. origin,
  469. glyphRun.runSize(),
  470. glyphRun.glyphsIDs().data(),
  471. glyphRun.positions().data(),
  472. fPositions,
  473. fPackedGlyphIDs);
  474. // Lookup all the glyphs from the cache.
  475. SkSpan<const SkGlyphPos> glyphPosSpan = strike->prepareForDrawing(
  476. packedGlyphIDs.data(),
  477. fPositions,
  478. glyphRun.runSize(),
  479. SkStrikeCommon::kSkSideTooBigForAtlas,
  480. SkStrikeInterface::kBoundsOnly,
  481. fGlyphPos);
  482. // Sort glyphs into the three bins: mask (fGlyphPos), path (fPaths), and fallback.
  483. size_t glyphsWithMaskCount = 0;
  484. for (const SkGlyphPos& glyphPos : glyphPosSpan) {
  485. const SkGlyph& glyph = *glyphPos.glyph;
  486. const SkPoint position = glyphPos.position;
  487. // Able to position glyph?
  488. if (!SkScalarsAreFinite(position.x(), position.y())) {
  489. continue;
  490. }
  491. if (glyph.maxDimension() <= SkStrikeCommon::kSkSideTooBigForAtlas) {
  492. fGlyphPos[glyphsWithMaskCount++] = glyphPos;
  493. } else if (!glyph.isColor()
  494. && glyph.path() != nullptr) {
  495. fPaths.push_back(glyphPos);
  496. } else {
  497. addFallback(glyph, origin + glyphRun.positions()[glyphPos.index]);
  498. }
  499. }
  500. if (process) {
  501. // processDeviceMasks must be called even if there are no glyphs to make sure runs
  502. // are set correctly.
  503. process->processDeviceMasks(
  504. SkSpan<const SkGlyphPos>{fGlyphPos, glyphsWithMaskCount}, strikeSpec);
  505. if (!fPaths.empty()) {
  506. process->processDevicePaths(SkMakeSpan(fPaths));
  507. }
  508. }
  509. // fGlyphPos will be reused here.
  510. if (!fARGBGlyphsIDs.empty()) {
  511. this->processARGBFallback(maxFallbackDimension / viewMatrix.getMaxScale(),
  512. runPaint, runFont, viewMatrix, process);
  513. }
  514. } // Mask case
  515. } // For all glyph runs
  516. }
  517. #endif // SK_SUPPORT_GPU
  518. auto SkGlyphRunListPainter::ensureBuffers(const SkGlyphRunList& glyphRunList) -> ScopedBuffers {
  519. size_t size = 0;
  520. for (const SkGlyphRun& run : glyphRunList) {
  521. size = std::max(run.runSize(), size);
  522. }
  523. return ScopedBuffers(this, size);
  524. }
  525. SkGlyphRunListPainter::ScopedBuffers
  526. SkGlyphRunListPainter::ensureBuffers(const SkGlyphRun& glyphRun) {
  527. return ScopedBuffers(this, glyphRun.runSize());
  528. }
  529. #if SK_SUPPORT_GPU
  530. // -- GrTextContext --------------------------------------------------------------------------------
  531. SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorSpaceInfo& colorSpaceInfo) {
  532. SkColor4f filteredColor = paint.getColor4f();
  533. if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) {
  534. filteredColor = xform->apply(filteredColor);
  535. }
  536. if (paint.getColorFilter() != nullptr) {
  537. filteredColor = paint.getColorFilter()->filterColor4f(filteredColor,
  538. colorSpaceInfo.colorSpace());
  539. }
  540. return filteredColor.premul();
  541. }
  542. void GrTextContext::drawGlyphRunList(
  543. GrRecordingContext* context, GrTextTarget* target, const GrClip& clip,
  544. const SkMatrix& viewMatrix, const SkSurfaceProps& props,
  545. const SkGlyphRunList& glyphRunList) {
  546. SkPoint origin = glyphRunList.origin();
  547. // Get the first paint to use as the key paint.
  548. const SkPaint& listPaint = glyphRunList.paint();
  549. SkPMColor4f filteredColor = generate_filtered_color(listPaint, target->colorSpaceInfo());
  550. GrColor color = generate_filtered_color(listPaint, target->colorSpaceInfo()).toBytes_RGBA();
  551. // If we have been abandoned, then don't draw
  552. if (context->priv().abandoned()) {
  553. return;
  554. }
  555. SkMaskFilterBase::BlurRec blurRec;
  556. // It might be worth caching these things, but its not clear at this time
  557. // TODO for animated mask filters, this will fill up our cache. We need a safeguard here
  558. const SkMaskFilter* mf = listPaint.getMaskFilter();
  559. bool canCache = glyphRunList.canCache() && !(listPaint.getPathEffect() ||
  560. (mf && !as_MFB(mf)->asABlur(&blurRec)));
  561. SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(target->colorSpaceInfo());
  562. auto grStrikeCache = context->priv().getGrStrikeCache();
  563. GrTextBlobCache* textBlobCache = context->priv().getTextBlobCache();
  564. sk_sp<GrTextBlob> cacheBlob;
  565. GrTextBlob::Key key;
  566. if (canCache) {
  567. bool hasLCD = glyphRunList.anyRunsLCD();
  568. // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry
  569. SkPixelGeometry pixelGeometry = hasLCD ? props.pixelGeometry() :
  570. kUnknown_SkPixelGeometry;
  571. // TODO we want to figure out a way to be able to use the canonical color on LCD text,
  572. // see the note on ComputeCanonicalColor above. We pick a dummy value for LCD text to
  573. // ensure we always match the same key
  574. GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT :
  575. ComputeCanonicalColor(listPaint, hasLCD);
  576. key.fPixelGeometry = pixelGeometry;
  577. key.fUniqueID = glyphRunList.uniqueID();
  578. key.fStyle = listPaint.getStyle();
  579. key.fHasBlur = SkToBool(mf);
  580. key.fCanonicalColor = canonicalColor;
  581. key.fScalerContextFlags = scalerContextFlags;
  582. cacheBlob = textBlobCache->find(key);
  583. }
  584. if (cacheBlob) {
  585. if (cacheBlob->mustRegenerate(listPaint, glyphRunList.anyRunsSubpixelPositioned(),
  586. blurRec, viewMatrix, origin.x(),origin.y())) {
  587. // We have to remake the blob because changes may invalidate our masks.
  588. // TODO we could probably get away reuse most of the time if the pointer is unique,
  589. // but we'd have to clear the subrun information
  590. textBlobCache->remove(cacheBlob.get());
  591. cacheBlob = textBlobCache->makeCachedBlob(
  592. glyphRunList, key, blurRec, listPaint, color, grStrikeCache);
  593. cacheBlob->generateFromGlyphRunList(
  594. *context->priv().caps()->shaderCaps(), fOptions,
  595. listPaint, scalerContextFlags, viewMatrix, props,
  596. glyphRunList, target->glyphPainter());
  597. } else {
  598. textBlobCache->makeMRU(cacheBlob.get());
  599. if (CACHE_SANITY_CHECK) {
  600. sk_sp<GrTextBlob> sanityBlob(textBlobCache->makeBlob(
  601. glyphRunList, color, grStrikeCache));
  602. sanityBlob->setupKey(key, blurRec, listPaint);
  603. cacheBlob->generateFromGlyphRunList(
  604. *context->priv().caps()->shaderCaps(), fOptions,
  605. listPaint, scalerContextFlags, viewMatrix, props, glyphRunList,
  606. target->glyphPainter());
  607. GrTextBlob::AssertEqual(*sanityBlob, *cacheBlob);
  608. }
  609. }
  610. } else {
  611. if (canCache) {
  612. cacheBlob = textBlobCache->makeCachedBlob(
  613. glyphRunList, key, blurRec, listPaint, color, grStrikeCache);
  614. } else {
  615. cacheBlob = textBlobCache->makeBlob(glyphRunList, color, grStrikeCache);
  616. }
  617. cacheBlob->generateFromGlyphRunList(
  618. *context->priv().caps()->shaderCaps(), fOptions, listPaint,
  619. scalerContextFlags, viewMatrix, props, glyphRunList,
  620. target->glyphPainter());
  621. }
  622. cacheBlob->flush(target, props, fDistanceAdjustTable.get(), listPaint, filteredColor,
  623. clip, viewMatrix, origin.x(), origin.y());
  624. }
  625. void GrTextBlob::SubRun::appendGlyph(GrGlyph* glyph, SkRect dstRect) {
  626. this->joinGlyphBounds(dstRect);
  627. GrTextBlob* blob = fRun->fBlob;
  628. bool hasW = this->hasWCoord();
  629. // glyphs drawn in perspective must always have a w coord.
  630. SkASSERT(hasW || !blob->fInitialViewMatrix.hasPerspective());
  631. auto maskFormat = this->maskFormat();
  632. size_t vertexStride = GetVertexStride(maskFormat, hasW);
  633. intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + fVertexEndIndex);
  634. // We always write the third position component used by SDFs. If it is unused it gets
  635. // overwritten. Similarly, we always write the color and the blob will later overwrite it
  636. // with texture coords if it is unused.
  637. size_t colorOffset = hasW ? sizeof(SkPoint3) : sizeof(SkPoint);
  638. // V0
  639. *reinterpret_cast<SkPoint3*>(vertex) = {dstRect.fLeft, dstRect.fTop, 1.f};
  640. *reinterpret_cast<GrColor*>(vertex + colorOffset) = fColor;
  641. vertex += vertexStride;
  642. // V1
  643. *reinterpret_cast<SkPoint3*>(vertex) = {dstRect.fLeft, dstRect.fBottom, 1.f};
  644. *reinterpret_cast<GrColor*>(vertex + colorOffset) = fColor;
  645. vertex += vertexStride;
  646. // V2
  647. *reinterpret_cast<SkPoint3*>(vertex) = {dstRect.fRight, dstRect.fTop, 1.f};
  648. *reinterpret_cast<GrColor*>(vertex + colorOffset) = fColor;
  649. vertex += vertexStride;
  650. // V3
  651. *reinterpret_cast<SkPoint3*>(vertex) = {dstRect.fRight, dstRect.fBottom, 1.f};
  652. *reinterpret_cast<GrColor*>(vertex + colorOffset) = fColor;
  653. fVertexEndIndex += vertexStride * kVerticesPerGlyph;
  654. blob->fGlyphs[fGlyphEndIndex++] = glyph;
  655. }
  656. void GrTextBlob::Run::switchSubRunIfNeededAndAppendGlyph(GrGlyph* glyph,
  657. const sk_sp<GrTextStrike>& strike,
  658. const SkRect& destRect,
  659. bool needsTransform) {
  660. GrMaskFormat format = glyph->fMaskFormat;
  661. SubRun* subRun = &fSubRunInfo.back();
  662. if (fInitialized && subRun->maskFormat() != format) {
  663. subRun = pushBackSubRun(fStrikeSpec, fColor);
  664. subRun->setStrike(strike);
  665. } else if (!fInitialized) {
  666. subRun->setStrike(strike);
  667. }
  668. fInitialized = true;
  669. subRun->setMaskFormat(format);
  670. subRun->setNeedsTransform(needsTransform);
  671. subRun->appendGlyph(glyph, destRect);
  672. }
  673. void GrTextBlob::Run::appendDeviceSpaceGlyph(const sk_sp<GrTextStrike>& strike,
  674. const SkGlyph& skGlyph, SkPoint origin) {
  675. if (GrGlyph* glyph = strike->getGlyph(skGlyph)) {
  676. SkRect glyphRect = glyph->destRect(origin);
  677. if (!glyphRect.isEmpty()) {
  678. this->switchSubRunIfNeededAndAppendGlyph(glyph, strike, glyphRect, false);
  679. }
  680. }
  681. }
  682. void GrTextBlob::Run::appendSourceSpaceGlyph(const sk_sp<GrTextStrike>& strike,
  683. const SkGlyph& skGlyph,
  684. SkPoint origin,
  685. SkScalar textScale) {
  686. if (GrGlyph* glyph = strike->getGlyph(skGlyph)) {
  687. SkRect glyphRect = glyph->destRect(origin, textScale);
  688. if (!glyphRect.isEmpty()) {
  689. this->switchSubRunIfNeededAndAppendGlyph(glyph, strike, glyphRect, true);
  690. }
  691. }
  692. }
  693. void GrTextBlob::generateFromGlyphRunList(const GrShaderCaps& shaderCaps,
  694. const GrTextContext::Options& options,
  695. const SkPaint& paint,
  696. SkScalerContextFlags scalerContextFlags,
  697. const SkMatrix& viewMatrix,
  698. const SkSurfaceProps& props,
  699. const SkGlyphRunList& glyphRunList,
  700. SkGlyphRunListPainter* glyphPainter) {
  701. SkPoint origin = glyphRunList.origin();
  702. const SkPaint& runPaint = glyphRunList.paint();
  703. this->initReusableBlob(SkPaintPriv::ComputeLuminanceColor(runPaint), viewMatrix,
  704. origin.x(), origin.y());
  705. glyphPainter->processGlyphRunList(glyphRunList,
  706. viewMatrix,
  707. props,
  708. shaderCaps.supportsDistanceFieldText(),
  709. options,
  710. this);
  711. }
  712. GrTextBlob::Run* GrTextBlob::currentRun() {
  713. return &fRuns[fRunCount - 1];
  714. }
  715. void GrTextBlob::startRun(const SkGlyphRun& glyphRun, bool useSDFT) {
  716. if (useSDFT) {
  717. this->setHasDistanceField();
  718. }
  719. Run* run = this->pushBackRun();
  720. run->setRunFontAntiAlias(glyphRun.font().hasSomeAntiAliasing());
  721. }
  722. void GrTextBlob::processDeviceMasks(SkSpan<const SkGlyphPos> masks,
  723. const SkStrikeSpec& strikeSpec) {
  724. Run* run = this->currentRun();
  725. this->setHasBitmap();
  726. run->setupFont(strikeSpec);
  727. sk_sp<GrTextStrike> currStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
  728. for (const auto& mask : masks) {
  729. SkPoint pt{SkScalarFloorToScalar(mask.position.fX),
  730. SkScalarFloorToScalar(mask.position.fY)};
  731. run->appendDeviceSpaceGlyph(currStrike, *mask.glyph, pt);
  732. }
  733. }
  734. void GrTextBlob::processSourcePaths(SkSpan<const SkGlyphPos> paths,
  735. const SkStrikeSpec& strikeSpec) {
  736. Run* run = this->currentRun();
  737. this->setHasBitmap();
  738. run->setupFont(strikeSpec);
  739. for (const auto& path : paths) {
  740. if (const SkPath* glyphPath = path.glyph->path()) {
  741. run->appendPathGlyph(*glyphPath, path.position, strikeSpec.strikeToSourceRatio(),
  742. false);
  743. }
  744. }
  745. }
  746. void GrTextBlob::processDevicePaths(SkSpan<const SkGlyphPos> paths) {
  747. Run* run = this->currentRun();
  748. this->setHasBitmap();
  749. for (const auto& path : paths) {
  750. SkPoint pt{SkScalarFloorToScalar(path.position.fX),
  751. SkScalarFloorToScalar(path.position.fY)};
  752. // TODO: path should always be set. Remove when proven.
  753. if (const SkPath* glyphPath = path.glyph->path()) {
  754. run->appendPathGlyph(*glyphPath, pt, SK_Scalar1, true);
  755. }
  756. }
  757. }
  758. void GrTextBlob::processSourceSDFT(SkSpan<const SkGlyphPos> masks,
  759. const SkStrikeSpec& strikeSpec,
  760. const SkFont& runFont,
  761. SkScalar minScale,
  762. SkScalar maxScale,
  763. bool hasWCoord) {
  764. Run* run = this->currentRun();
  765. run->setSubRunHasDistanceFields(
  766. runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
  767. runFont.hasSomeAntiAliasing(),
  768. hasWCoord);
  769. this->setMinAndMaxScale(minScale, maxScale);
  770. run->setupFont(strikeSpec);
  771. sk_sp<GrTextStrike> currStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
  772. for (const auto& mask : masks) {
  773. run->appendSourceSpaceGlyph(
  774. currStrike, *mask.glyph, mask.position, strikeSpec.strikeToSourceRatio());
  775. }
  776. }
  777. void GrTextBlob::processSourceFallback(SkSpan<const SkGlyphPos> masks,
  778. const SkStrikeSpec& strikeSpec,
  779. bool hasW) {
  780. Run* run = this->currentRun();
  781. auto subRun = run->initARGBFallback();
  782. sk_sp<GrTextStrike> grStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
  783. subRun->setStrike(grStrike);
  784. subRun->setHasWCoord(hasW);
  785. this->setHasBitmap();
  786. run->setupFont(strikeSpec);
  787. for (const auto& mask : masks) {
  788. run->appendSourceSpaceGlyph
  789. (grStrike, *mask.glyph, mask.position, strikeSpec.strikeToSourceRatio());
  790. }
  791. }
  792. void GrTextBlob::processDeviceFallback(SkSpan<const SkGlyphPos> masks,
  793. const SkStrikeSpec& strikeSpec) {
  794. Run* run = this->currentRun();
  795. this->setHasBitmap();
  796. sk_sp<GrTextStrike> grStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
  797. auto subRun = run->initARGBFallback();
  798. run->setupFont(strikeSpec);
  799. subRun->setStrike(grStrike);
  800. for (const auto& mask : masks) {
  801. run->appendDeviceSpaceGlyph(grStrike, *mask.glyph, mask.position);
  802. }
  803. }
  804. #if GR_TEST_UTILS
  805. #include "src/gpu/GrRecordingContextPriv.h"
  806. #include "src/gpu/GrRenderTargetContext.h"
  807. std::unique_ptr<GrDrawOp> GrTextContext::createOp_TestingOnly(GrRecordingContext* context,
  808. GrTextContext* textContext,
  809. GrRenderTargetContext* rtc,
  810. const SkPaint& skPaint,
  811. const SkFont& font,
  812. const SkMatrix& viewMatrix,
  813. const char* text,
  814. int x,
  815. int y) {
  816. auto direct = context->priv().asDirectContext();
  817. if (!direct) {
  818. return nullptr;
  819. }
  820. auto strikeCache = direct->priv().getGrStrikeCache();
  821. static SkSurfaceProps surfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
  822. size_t textLen = (int)strlen(text);
  823. SkPMColor4f filteredColor = generate_filtered_color(skPaint, rtc->colorSpaceInfo());
  824. GrColor color = filteredColor.toBytes_RGBA();
  825. auto origin = SkPoint::Make(x, y);
  826. SkGlyphRunBuilder builder;
  827. builder.drawTextUTF8(skPaint, font, text, textLen, origin);
  828. auto glyphRunList = builder.useGlyphRunList();
  829. sk_sp<GrTextBlob> blob;
  830. if (!glyphRunList.empty()) {
  831. blob = direct->priv().getTextBlobCache()->makeBlob(glyphRunList, color, strikeCache);
  832. // Use the text and textLen below, because we don't want to mess with the paint.
  833. SkScalerContextFlags scalerContextFlags =
  834. ComputeScalerContextFlags(rtc->colorSpaceInfo());
  835. blob->generateFromGlyphRunList(
  836. *context->priv().caps()->shaderCaps(), textContext->fOptions,
  837. skPaint, scalerContextFlags, viewMatrix, surfaceProps,
  838. glyphRunList, rtc->textTarget()->glyphPainter());
  839. }
  840. return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, skPaint, filteredColor, surfaceProps,
  841. textContext->dfAdjustTable(), rtc->textTarget());
  842. }
  843. #endif // GR_TEST_UTILS
  844. #endif // SK_SUPPORT_GPU
  845. SkGlyphRunListPainter::ScopedBuffers::ScopedBuffers(SkGlyphRunListPainter* painter, int size)
  846. : fPainter{painter} {
  847. SkASSERT(size >= 0);
  848. if (fPainter->fMaxRunSize < size) {
  849. fPainter->fMaxRunSize = size;
  850. fPainter->fPositions.reset(size);
  851. fPainter->fPackedGlyphIDs.reset(size);
  852. fPainter->fGlyphPos.reset(size);
  853. }
  854. }
  855. SkGlyphRunListPainter::ScopedBuffers::~ScopedBuffers() {
  856. fPainter->fPaths.clear();
  857. fPainter->fARGBGlyphsIDs.clear();
  858. fPainter->fARGBPositions.clear();
  859. if (fPainter->fMaxRunSize > 200) {
  860. fPainter->fMaxRunSize = 0;
  861. fPainter->fPositions.reset();
  862. fPainter->fPackedGlyphIDs.reset();
  863. fPainter->fGlyphPos.reset();
  864. fPainter->fPaths.shrink_to_fit();
  865. fPainter->fARGBGlyphsIDs.shrink_to_fit();
  866. fPainter->fARGBPositions.shrink_to_fit();
  867. }
  868. }