| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |