Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: third_party/WebKit/Source/platform/fonts/Font.cpp

Issue 2714413003: Remove GlyphBuffer (Closed)
Patch Set: format Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org) 4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. 5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. 6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved.
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 13 matching lines...) Expand all
24 24
25 #include "platform/fonts/Font.h" 25 #include "platform/fonts/Font.h"
26 26
27 #include "platform/LayoutTestSupport.h" 27 #include "platform/LayoutTestSupport.h"
28 #include "platform/LayoutUnit.h" 28 #include "platform/LayoutUnit.h"
29 #include "platform/RuntimeEnabledFeatures.h" 29 #include "platform/RuntimeEnabledFeatures.h"
30 #include "platform/fonts/CharacterRange.h" 30 #include "platform/fonts/CharacterRange.h"
31 #include "platform/fonts/FontCache.h" 31 #include "platform/fonts/FontCache.h"
32 #include "platform/fonts/FontFallbackIterator.h" 32 #include "platform/fonts/FontFallbackIterator.h"
33 #include "platform/fonts/FontFallbackList.h" 33 #include "platform/fonts/FontFallbackList.h"
34 #include "platform/fonts/GlyphBuffer.h"
35 #include "platform/fonts/SimpleFontData.h" 34 #include "platform/fonts/SimpleFontData.h"
36 #include "platform/fonts/shaping/CachingWordShaper.h" 35 #include "platform/fonts/shaping/CachingWordShaper.h"
36 #include "platform/fonts/shaping/ShapeResultBloberizer.h"
37 #include "platform/geometry/FloatRect.h" 37 #include "platform/geometry/FloatRect.h"
38 #include "platform/graphics/paint/PaintCanvas.h" 38 #include "platform/graphics/paint/PaintCanvas.h"
39 #include "platform/graphics/paint/PaintFlags.h" 39 #include "platform/graphics/paint/PaintFlags.h"
40 #include "platform/text/BidiResolver.h" 40 #include "platform/text/BidiResolver.h"
41 #include "platform/text/Character.h" 41 #include "platform/text/Character.h"
42 #include "platform/text/TextRun.h" 42 #include "platform/text/TextRun.h"
43 #include "platform/text/TextRunIterator.h" 43 #include "platform/text/TextRunIterator.h"
44 #include "platform/transforms/AffineTransform.h" 44 #include "platform/transforms/AffineTransform.h"
45 #include "third_party/skia/include/core/SkTextBlob.h" 45 #include "third_party/skia/include/core/SkTextBlob.h"
46 #include "wtf/StdLibExtras.h" 46 #include "wtf/StdLibExtras.h"
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 // but it ends up being reasonably safe (because inherited fonts in the render 98 // but it ends up being reasonably safe (because inherited fonts in the render
99 // tree pick up the new style anyway. Other copies are transient, e.g., the 99 // tree pick up the new style anyway. Other copies are transient, e.g., the
100 // state in the GraphicsContext, and won't stick around long enough to get you 100 // state in the GraphicsContext, and won't stick around long enough to get you
101 // in trouble). Still, this is pretty disgusting, and could eventually be 101 // in trouble). Still, this is pretty disgusting, and could eventually be
102 // rectified by using RefPtrs for Fonts themselves. 102 // rectified by using RefPtrs for Fonts themselves.
103 if (!m_fontFallbackList) 103 if (!m_fontFallbackList)
104 m_fontFallbackList = FontFallbackList::create(); 104 m_fontFallbackList = FontFallbackList::create();
105 m_fontFallbackList->invalidate(fontSelector); 105 m_fontFallbackList->invalidate(fontSelector);
106 } 106 }
107 107
108 float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, 108 namespace {
109 GlyphBuffer& glyphBuffer, 109
110 const GlyphData* emphasisData) const { 110 void drawBlobs(PaintCanvas* canvas,
111 float width; 111 const PaintFlags& flags,
112 CachingWordShaper shaper(*this); 112 const ShapeResultBloberizer::BlobBuffer& blobs,
113 if (emphasisData) { 113 const FloatPoint& point) {
114 width = shaper.fillGlyphBufferForTextEmphasis(runInfo.run, 114 for (const auto& blobInfo : blobs) {
115 emphasisData, &glyphBuffer, 115 DCHECK(blobInfo.blob);
116 runInfo.from, runInfo.to); 116 PaintCanvasAutoRestore autoRestore(canvas, false);
117 } else { 117 if (blobInfo.rotation == ShapeResultBloberizer::BlobRotation::CCWRotation) {
118 width = shaper.fillGlyphBuffer(runInfo.run, &glyphBuffer, 118 canvas->save();
119 runInfo.from, runInfo.to); 119
120 SkMatrix m;
121 m.setSinCos(-1, 0, point.x(), point.y());
122 canvas->concat(m);
123 }
124
125 canvas->drawTextBlob(blobInfo.blob, point.x(), point.y(), flags);
120 } 126 }
121 return width;
122 } 127 }
123 128
129 } // anonymous ns
130
124 bool Font::drawText(PaintCanvas* canvas, 131 bool Font::drawText(PaintCanvas* canvas,
125 const TextRunPaintInfo& runInfo, 132 const TextRunPaintInfo& runInfo,
126 const FloatPoint& point, 133 const FloatPoint& point,
127 float deviceScaleFactor, 134 float deviceScaleFactor,
128 const PaintFlags& flags) const { 135 const PaintFlags& flags) const {
129 // Don't draw anything while we are using custom fonts that are in the process 136 // Don't draw anything while we are using custom fonts that are in the process
130 // of loading. 137 // of loading.
131 if (shouldSkipDrawing()) 138 if (shouldSkipDrawing())
132 return false; 139 return false;
133 140
134 GlyphBuffer glyphBuffer; 141 ShapeResultBloberizer bloberizer(*this, deviceScaleFactor);
135 buildGlyphBuffer(runInfo, glyphBuffer); 142 CachingWordShaper(*this).fillGlyphs(runInfo, bloberizer);
136 143 drawBlobs(canvas, flags, bloberizer.blobs(), point);
137 drawGlyphBuffer(canvas, flags, glyphBuffer, point, deviceScaleFactor);
138 return true; 144 return true;
139 } 145 }
140 146
141 bool Font::drawBidiText(PaintCanvas* canvas, 147 bool Font::drawBidiText(PaintCanvas* canvas,
142 const TextRunPaintInfo& runInfo, 148 const TextRunPaintInfo& runInfo,
143 const FloatPoint& point, 149 const FloatPoint& point,
144 CustomFontNotReadyAction customFontNotReadyAction, 150 CustomFontNotReadyAction customFontNotReadyAction,
145 float deviceScaleFactor, 151 float deviceScaleFactor,
146 const PaintFlags& flags) const { 152 const PaintFlags& flags) const {
147 // Don't draw anything while we are using custom fonts that are in the process 153 // Don't draw anything while we are using custom fonts that are in the process
(...skipping 23 matching lines...) Expand all
171 while (bidiRun) { 177 while (bidiRun) {
172 TextRun subrun = 178 TextRun subrun =
173 run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start()); 179 run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
174 bool isRTL = bidiRun->level() % 2; 180 bool isRTL = bidiRun->level() % 2;
175 subrun.setDirection(isRTL ? TextDirection::kRtl : TextDirection::kLtr); 181 subrun.setDirection(isRTL ? TextDirection::kRtl : TextDirection::kLtr);
176 subrun.setDirectionalOverride(bidiRun->dirOverride(false)); 182 subrun.setDirectionalOverride(bidiRun->dirOverride(false));
177 183
178 TextRunPaintInfo subrunInfo(subrun); 184 TextRunPaintInfo subrunInfo(subrun);
179 subrunInfo.bounds = runInfo.bounds; 185 subrunInfo.bounds = runInfo.bounds;
180 186
181 // TODO: investigate blob consolidation/caching (technically, 187 ShapeResultBloberizer bloberizer(*this, deviceScaleFactor);
182 // all subruns could be part of the same blob). 188 float runWidth =
183 GlyphBuffer glyphBuffer; 189 CachingWordShaper(*this).fillGlyphs(subrunInfo, bloberizer);
184 float runWidth = buildGlyphBuffer(subrunInfo, glyphBuffer); 190 drawBlobs(canvas, flags, bloberizer.blobs(), currPoint);
185 drawGlyphBuffer(canvas, flags, glyphBuffer, currPoint, deviceScaleFactor);
186 191
187 bidiRun = bidiRun->next(); 192 bidiRun = bidiRun->next();
188 currPoint.move(runWidth, 0); 193 currPoint.move(runWidth, 0);
189 } 194 }
190 195
191 bidiRuns.deleteRuns(); 196 bidiRuns.deleteRuns();
192 return true; 197 return true;
193 } 198 }
194 199
195 void Font::drawEmphasisMarks(PaintCanvas* canvas, 200 void Font::drawEmphasisMarks(PaintCanvas* canvas,
196 const TextRunPaintInfo& runInfo, 201 const TextRunPaintInfo& runInfo,
197 const AtomicString& mark, 202 const AtomicString& mark,
198 const FloatPoint& point, 203 const FloatPoint& point,
199 float deviceScaleFactor, 204 float deviceScaleFactor,
200 const PaintFlags& flags) const { 205 const PaintFlags& flags) const {
201 if (shouldSkipDrawing()) 206 if (shouldSkipDrawing())
202 return; 207 return;
203 208
204 FontCachePurgePreventer purgePreventer; 209 FontCachePurgePreventer purgePreventer;
205 210
206 const auto emphasisGlyphData = getEmphasisMarkGlyphData(mark); 211 const auto emphasisGlyphData = getEmphasisMarkGlyphData(mark);
207 if (!emphasisGlyphData.fontData) 212 if (!emphasisGlyphData.fontData)
208 return; 213 return;
209 214
210 GlyphBuffer glyphBuffer; 215 ShapeResultBloberizer bloberizer(*this, deviceScaleFactor);
211 buildGlyphBuffer(runInfo, glyphBuffer, &emphasisGlyphData); 216 CachingWordShaper(*this).fillTextEmphasisGlyphs(runInfo, emphasisGlyphData,
212 217 bloberizer);
213 if (glyphBuffer.isEmpty()) 218 drawBlobs(canvas, flags, bloberizer.blobs(), point);
214 return;
215
216 drawGlyphBuffer(canvas, flags, glyphBuffer, point, deviceScaleFactor);
217 } 219 }
218 220
219 float Font::width(const TextRun& run, 221 float Font::width(const TextRun& run,
220 HashSet<const SimpleFontData*>* fallbackFonts, 222 HashSet<const SimpleFontData*>* fallbackFonts,
221 FloatRect* glyphBounds) const { 223 FloatRect* glyphBounds) const {
222 FontCachePurgePreventer purgePreventer; 224 FontCachePurgePreventer purgePreventer;
223 CachingWordShaper shaper(*this); 225 CachingWordShaper shaper(*this);
224 return shaper.width(run, fallbackFonts, glyphBounds); 226 return shaper.width(run, fallbackFonts, glyphBounds);
225 } 227 }
226 228
227 namespace { 229 static int getInterceptsFromBlobs(
228 230 const ShapeResultBloberizer::BlobBuffer& blobs,
229 enum BlobRotation { 231 const SkPaint& paint,
230 NoRotation, 232 const std::tuple<float, float>& bounds,
231 CCWRotation, 233 SkScalar* interceptsBuffer) {
232 };
233
234 class GlyphBufferBloberizer {
235 STACK_ALLOCATED()
236 public:
237 GlyphBufferBloberizer(const GlyphBuffer& buffer,
238 const Font* font,
239 float deviceScaleFactor)
240 : m_buffer(buffer),
241 m_font(font),
242 m_deviceScaleFactor(deviceScaleFactor),
243 m_hasVerticalOffsets(buffer.hasVerticalOffsets()),
244 m_index(0),
245 m_endIndex(m_buffer.size()),
246 m_rotation(buffer.isEmpty() ? NoRotation : computeBlobRotation(
247 buffer.fontDataAt(0))) {}
248
249 bool done() const { return m_index >= m_endIndex; }
250
251 std::pair<sk_sp<SkTextBlob>, BlobRotation> next() {
252 ASSERT(!done());
253 const BlobRotation currentRotation = m_rotation;
254
255 while (m_index < m_endIndex) {
256 const SimpleFontData* fontData = m_buffer.fontDataAt(m_index);
257 ASSERT(fontData);
258
259 const BlobRotation newRotation = computeBlobRotation(fontData);
260 if (newRotation != m_rotation) {
261 // We're switching to an orientation which requires a different rotation
262 // => emit the pending blob (and start a new one with the new
263 // rotation).
264 m_rotation = newRotation;
265 break;
266 }
267
268 const unsigned start = m_index++;
269 while (m_index < m_endIndex && m_buffer.fontDataAt(m_index) == fontData)
270 m_index++;
271
272 appendRun(start, m_index - start, fontData);
273 }
274
275 return std::make_pair(m_builder.make(), currentRotation);
276 }
277
278 private:
279 static BlobRotation computeBlobRotation(const SimpleFontData* font) {
280 // For vertical upright text we need to compensate the inherited 90deg CW
281 // rotation (using a 90deg CCW rotation).
282 return (font->platformData().isVerticalAnyUpright() && font->verticalData())
283 ? CCWRotation
284 : NoRotation;
285 }
286
287 void appendRun(unsigned start,
288 unsigned count,
289 const SimpleFontData* fontData) {
290 SkPaint paint;
291 fontData->platformData().setupPaint(&paint, m_deviceScaleFactor, m_font);
292 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
293
294 const SkTextBlobBuilder::RunBuffer& buffer =
295 m_hasVerticalOffsets ? m_builder.allocRunPos(paint, count)
296 : m_builder.allocRunPosH(paint, count, 0);
297
298 const uint16_t* glyphs = m_buffer.glyphs(start);
299 const float* offsets = m_buffer.offsets(start);
300 std::copy(glyphs, glyphs + count, buffer.glyphs);
301
302 if (m_rotation == NoRotation) {
303 std::copy(offsets, offsets + (m_hasVerticalOffsets ? 2 * count : count),
304 buffer.pos);
305 } else {
306 ASSERT(m_hasVerticalOffsets);
307
308 const float verticalBaselineXOffset =
309 fontData->getFontMetrics().floatAscent() -
310 fontData->getFontMetrics().floatAscent(IdeographicBaseline);
311
312 // TODO(fmalita): why don't we apply this adjustment when building the
313 // glyph buffer?
314 for (unsigned i = 0; i < 2 * count; i += 2) {
315 buffer.pos[i] = SkFloatToScalar(offsets[i] + verticalBaselineXOffset);
316 buffer.pos[i + 1] = SkFloatToScalar(offsets[i + 1]);
317 }
318 }
319 }
320
321 const GlyphBuffer& m_buffer;
322 const Font* m_font;
323 const float m_deviceScaleFactor;
324 const bool m_hasVerticalOffsets;
325
326 SkTextBlobBuilder m_builder;
327 unsigned m_index;
328 unsigned m_endIndex;
329 BlobRotation m_rotation;
330 };
331
332 } // anonymous namespace
333
334 void Font::drawGlyphBuffer(PaintCanvas* canvas,
335 const PaintFlags& flags,
336 const GlyphBuffer& glyphBuffer,
337 const FloatPoint& point,
338 float deviceScaleFactor) const {
339 GlyphBufferBloberizer bloberizer(glyphBuffer, this, deviceScaleFactor);
340
341 while (!bloberizer.done()) {
342 auto blob = bloberizer.next();
343 ASSERT(blob.first);
344
345 PaintCanvasAutoRestore autoRestore(canvas, false);
346 if (blob.second == CCWRotation) {
347 canvas->save();
348
349 SkMatrix m;
350 m.setSinCos(-1, 0, point.x(), point.y());
351 canvas->concat(m);
352 }
353
354 canvas->drawTextBlob(blob.first, point.x(), point.y(), flags);
355 }
356 }
357
358 static int getInterceptsFromBloberizer(const GlyphBuffer& glyphBuffer,
359 const Font* font,
360 const SkPaint& paint,
361 float deviceScaleFactor,
362 const std::tuple<float, float>& bounds,
363 SkScalar* interceptsBuffer) {
364 SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)}; 234 SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)};
365 GlyphBufferBloberizer bloberizer(glyphBuffer, font, deviceScaleFactor);
366 235
367 int numIntervals = 0; 236 int numIntervals = 0;
368 while (!bloberizer.done()) { 237 for (const auto& blobInfo : blobs) {
369 auto blob = bloberizer.next(); 238 DCHECK(blobInfo.blob);
370 DCHECK(blob.first);
371 239
372 // GlyphBufferBloberizer splits for a new blob rotation, but does not split 240 // ShapeResultBloberizer splits for a new blob rotation, but does not split
373 // for a change in font. A TextBlob can contain runs with differing fonts 241 // for a change in font. A TextBlob can contain runs with differing fonts
374 // and the getTextBlobIntercepts method handles multiple fonts for us. For 242 // and the getTextBlobIntercepts method handles multiple fonts for us. For
375 // upright in vertical blobs we currently have to bail, see crbug.com/655154 243 // upright in vertical blobs we currently have to bail, see crbug.com/655154
376 if (blob.second == BlobRotation::CCWRotation) 244 if (blobInfo.rotation == ShapeResultBloberizer::BlobRotation::CCWRotation)
377 continue; 245 continue;
378 246
379 SkScalar* offsetInterceptsBuffer = nullptr; 247 SkScalar* offsetInterceptsBuffer = nullptr;
380 if (interceptsBuffer) 248 if (interceptsBuffer)
381 offsetInterceptsBuffer = &interceptsBuffer[numIntervals]; 249 offsetInterceptsBuffer = &interceptsBuffer[numIntervals];
382 numIntervals += paint.getTextBlobIntercepts(blob.first.get(), boundsArray, 250 numIntervals += paint.getTextBlobIntercepts(
383 offsetInterceptsBuffer); 251 blobInfo.blob.get(), boundsArray, offsetInterceptsBuffer);
384 } 252 }
385 return numIntervals; 253 return numIntervals;
386 } 254 }
387 255
388 void Font::getTextIntercepts(const TextRunPaintInfo& runInfo, 256 void Font::getTextIntercepts(const TextRunPaintInfo& runInfo,
389 float deviceScaleFactor, 257 float deviceScaleFactor,
390 const PaintFlags& flags, 258 const PaintFlags& flags,
391 const std::tuple<float, float>& bounds, 259 const std::tuple<float, float>& bounds,
392 Vector<TextIntercept>& intercepts) const { 260 Vector<TextIntercept>& intercepts) const {
393 if (shouldSkipDrawing()) 261 if (shouldSkipDrawing())
394 return; 262 return;
395 263
396 GlyphBuffer glyphBuffer(GlyphBuffer::Type::TextIntercepts); 264 ShapeResultBloberizer bloberizer(*this, deviceScaleFactor,
397 buildGlyphBuffer(runInfo, glyphBuffer); 265 ShapeResultBloberizer::Type::TextIntercepts);
266 CachingWordShaper(*this).fillGlyphs(runInfo, bloberizer);
267 const auto& blobs = bloberizer.blobs();
398 268
399 // Get the number of intervals, without copying the actual values by 269 // Get the number of intervals, without copying the actual values by
400 // specifying nullptr for the buffer, following the Skia allocation model for 270 // specifying nullptr for the buffer, following the Skia allocation model for
401 // retrieving text intercepts. 271 // retrieving text intercepts.
402 SkPaint paint(ToSkPaint(flags)); 272 SkPaint paint(ToSkPaint(flags));
403 int numIntervals = getInterceptsFromBloberizer( 273 int numIntervals = getInterceptsFromBlobs(blobs, paint, bounds, nullptr);
404 glyphBuffer, this, paint, deviceScaleFactor, bounds, nullptr);
405 if (!numIntervals) 274 if (!numIntervals)
406 return; 275 return;
407 DCHECK_EQ(numIntervals % 2, 0); 276 DCHECK_EQ(numIntervals % 2, 0);
408 intercepts.resize(numIntervals / 2); 277 intercepts.resize(numIntervals / 2);
409 278
410 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor, 279 getInterceptsFromBlobs(blobs, paint, bounds,
411 bounds, 280 reinterpret_cast<SkScalar*>(intercepts.data()));
412 reinterpret_cast<SkScalar*>(intercepts.data()));
413 } 281 }
414 282
415 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) { 283 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) {
416 // Using roundf() rather than ceilf() for the right edge as a compromise to 284 // Using roundf() rather than ceilf() for the right edge as a compromise to
417 // ensure correct caret positioning. 285 // ensure correct caret positioning.
418 float roundedX = roundf(rect.x()); 286 float roundedX = roundf(rect.x());
419 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), 287 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX),
420 rect.height()); 288 rect.height());
421 } 289 }
422 290
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 419
552 bool Font::loadingCustomFonts() const { 420 bool Font::loadingCustomFonts() const {
553 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); 421 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts();
554 } 422 }
555 423
556 bool Font::isFallbackValid() const { 424 bool Font::isFallbackValid() const {
557 return !m_fontFallbackList || m_fontFallbackList->isValid(); 425 return !m_fontFallbackList || m_fontFallbackList->isValid();
558 } 426 }
559 427
560 } // namespace blink 428 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698