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 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 STACK_ALLOCATED() | 250 STACK_ALLOCATED() |
251 public: | 251 public: |
252 GlyphBufferBloberizer(const GlyphBuffer& buffer, | 252 GlyphBufferBloberizer(const GlyphBuffer& buffer, |
253 const Font* font, | 253 const Font* font, |
254 float deviceScaleFactor) | 254 float deviceScaleFactor) |
255 : m_buffer(buffer), | 255 : m_buffer(buffer), |
256 m_font(font), | 256 m_font(font), |
257 m_deviceScaleFactor(deviceScaleFactor), | 257 m_deviceScaleFactor(deviceScaleFactor), |
258 m_hasVerticalOffsets(buffer.hasVerticalOffsets()), | 258 m_hasVerticalOffsets(buffer.hasVerticalOffsets()), |
259 m_index(0), | 259 m_index(0), |
260 m_endIndex(m_buffer.size()), | |
260 m_blobCount(0), | 261 m_blobCount(0), |
261 m_rotation(buffer.isEmpty() ? NoRotation : computeBlobRotation( | 262 m_rotation(buffer.isEmpty() ? NoRotation : computeBlobRotation( |
262 buffer.fontDataAt(0))) {} | 263 buffer.fontDataAt(0))), |
264 m_skipGlyphs(nullptr) {} | |
263 | 265 |
264 bool done() const { return m_index >= m_buffer.size(); } | 266 bool done() const { return m_index >= m_endIndex; } |
265 unsigned blobCount() const { return m_blobCount; } | 267 unsigned blobCount() const { return m_blobCount; } |
266 | 268 |
267 std::pair<sk_sp<SkTextBlob>, BlobRotation> next() { | 269 std::pair<sk_sp<SkTextBlob>, BlobRotation> next() { |
268 ASSERT(!done()); | 270 ASSERT(!done()); |
269 const BlobRotation currentRotation = m_rotation; | 271 const BlobRotation currentRotation = m_rotation; |
270 | 272 |
271 while (m_index < m_buffer.size()) { | 273 while (m_index < m_endIndex) { |
274 if (m_skipGlyphs) { | |
275 while (m_index < m_endIndex && (*m_skipGlyphs)[m_index]) | |
276 m_index++; | |
277 } | |
278 | |
272 const SimpleFontData* fontData = m_buffer.fontDataAt(m_index); | 279 const SimpleFontData* fontData = m_buffer.fontDataAt(m_index); |
273 ASSERT(fontData); | 280 ASSERT(fontData); |
274 | 281 |
275 const BlobRotation newRotation = computeBlobRotation(fontData); | 282 const BlobRotation newRotation = computeBlobRotation(fontData); |
276 if (newRotation != m_rotation) { | 283 if (newRotation != m_rotation) { |
277 // We're switching to an orientation which requires a different rotation | 284 // We're switching to an orientation which requires a different rotation |
278 // => emit the pending blob (and start a new one with the new | 285 // => emit the pending blob (and start a new one with the new |
279 // rotation). | 286 // rotation). |
280 m_rotation = newRotation; | 287 m_rotation = newRotation; |
281 break; | 288 break; |
282 } | 289 } |
283 | 290 |
284 const unsigned start = m_index++; | 291 const unsigned start = m_index++; |
285 while (m_index < m_buffer.size() && | 292 while (m_index < m_endIndex && m_buffer.fontDataAt(m_index) == fontData && |
286 m_buffer.fontDataAt(m_index) == fontData) | 293 !(m_skipGlyphs && (*m_skipGlyphs)[m_index])) |
287 m_index++; | 294 m_index++; |
288 | 295 |
289 appendRun(start, m_index - start, fontData); | 296 appendRun(start, m_index - start, fontData); |
290 } | 297 } |
291 | 298 |
292 m_blobCount++; | 299 m_blobCount++; |
293 return std::make_pair(m_builder.make(), currentRotation); | 300 return std::make_pair(m_builder.make(), currentRotation); |
294 } | 301 } |
295 | 302 |
303 void setSkipGlyphs(const Vector<bool>* skipGlyphs) { | |
304 m_skipGlyphs = skipGlyphs; | |
305 m_endIndex = m_buffer.size(); | |
306 if (m_skipGlyphs) { | |
307 while (m_endIndex > 0 && (*m_skipGlyphs)[m_endIndex - 1]) | |
308 m_endIndex--; | |
309 } | |
310 } | |
311 | |
296 private: | 312 private: |
297 static BlobRotation computeBlobRotation(const SimpleFontData* font) { | 313 static BlobRotation computeBlobRotation(const SimpleFontData* font) { |
298 // For vertical upright text we need to compensate the inherited 90deg CW | 314 // For vertical upright text we need to compensate the inherited 90deg CW |
299 // rotation (using a 90deg CCW rotation). | 315 // rotation (using a 90deg CCW rotation). |
300 return (font->platformData().isVerticalAnyUpright() && font->verticalData()) | 316 return (font->platformData().isVerticalAnyUpright() && font->verticalData()) |
301 ? CCWRotation | 317 ? CCWRotation |
302 : NoRotation; | 318 : NoRotation; |
303 } | 319 } |
304 | 320 |
305 void appendRun(unsigned start, | 321 void appendRun(unsigned start, |
(...skipping 30 matching lines...) Expand all Loading... | |
336 } | 352 } |
337 } | 353 } |
338 | 354 |
339 const GlyphBuffer& m_buffer; | 355 const GlyphBuffer& m_buffer; |
340 const Font* m_font; | 356 const Font* m_font; |
341 const float m_deviceScaleFactor; | 357 const float m_deviceScaleFactor; |
342 const bool m_hasVerticalOffsets; | 358 const bool m_hasVerticalOffsets; |
343 | 359 |
344 SkTextBlobBuilder m_builder; | 360 SkTextBlobBuilder m_builder; |
345 unsigned m_index; | 361 unsigned m_index; |
362 unsigned m_endIndex; | |
346 unsigned m_blobCount; | 363 unsigned m_blobCount; |
347 BlobRotation m_rotation; | 364 BlobRotation m_rotation; |
365 const Vector<bool>* m_skipGlyphs; | |
348 }; | 366 }; |
349 | 367 |
350 } // anonymous namespace | 368 } // anonymous namespace |
351 | 369 |
352 void Font::drawGlyphBuffer(SkCanvas* canvas, | 370 void Font::drawGlyphBuffer(SkCanvas* canvas, |
353 const SkPaint& paint, | 371 const SkPaint& paint, |
354 const TextRunPaintInfo& runInfo, | 372 const TextRunPaintInfo& runInfo, |
355 const GlyphBuffer& glyphBuffer, | 373 const GlyphBuffer& glyphBuffer, |
356 const FloatPoint& point, | 374 const FloatPoint& point, |
357 float deviceScaleFactor) const { | 375 float deviceScaleFactor) const { |
(...skipping 21 matching lines...) Expand all Loading... | |
379 // 2) the glyph buffer is encoded as a single blob, and | 397 // 2) the glyph buffer is encoded as a single blob, and |
380 // 3) the blob is not upright/rotated | 398 // 3) the blob is not upright/rotated |
381 if (runInfo.cachedTextBlob && bloberizer.blobCount() == 1 && | 399 if (runInfo.cachedTextBlob && bloberizer.blobCount() == 1 && |
382 blob.second == NoRotation) { | 400 blob.second == NoRotation) { |
383 ASSERT(!*runInfo.cachedTextBlob); | 401 ASSERT(!*runInfo.cachedTextBlob); |
384 *runInfo.cachedTextBlob = std::move(blob.first); | 402 *runInfo.cachedTextBlob = std::move(blob.first); |
385 ASSERT(*runInfo.cachedTextBlob); | 403 ASSERT(*runInfo.cachedTextBlob); |
386 } | 404 } |
387 } | 405 } |
388 | 406 |
407 static std::unique_ptr<Vector<bool>> glyphsToSkipIntercepts( | |
408 const TextRun& run, | |
409 const GlyphBuffer& glyphBuffer) { | |
410 // Skipping ink leads to undesirable renderings for some scripts. Determine | |
411 // glyphs not to skip ink on a character-by-character basis. | |
412 DCHECK(!run.is8Bit()); | |
413 std::unique_ptr<Vector<bool>> skipIndexes = | |
414 WTF::makeUnique<Vector<bool>>(glyphBuffer.size()); | |
415 bool hasAnySkip = false; | |
416 for (unsigned index = 0; index < glyphBuffer.size(); index++) { | |
417 unsigned characterIndex = glyphBuffer.characterIndex(index); | |
418 UChar32 baseCharacter = run.codepointAt(characterIndex); | |
drott
2017/01/02 15:07:45
Can we reuse Character::isCJKIdeographOrSymbol for
| |
419 UBlockCode blockCode = ublock_getCode(baseCharacter); | |
420 switch (blockCode) { | |
421 case UBLOCK_BOPOMOFO: | |
422 case UBLOCK_BOPOMOFO_EXTENDED: | |
423 case UBLOCK_CJK_COMPATIBILITY: | |
424 case UBLOCK_CJK_COMPATIBILITY_FORMS: | |
425 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS: | |
426 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT: | |
427 case UBLOCK_CJK_RADICALS_SUPPLEMENT: | |
428 case UBLOCK_CJK_STROKES: | |
429 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: | |
430 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS: | |
431 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A: | |
432 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B: | |
433 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C: | |
434 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D: | |
435 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E: | |
436 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: | |
437 case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT: | |
438 case UBLOCK_HANGUL_COMPATIBILITY_JAMO: | |
439 case UBLOCK_HANGUL_JAMO: | |
440 case UBLOCK_HANGUL_JAMO_EXTENDED_A: | |
441 case UBLOCK_HANGUL_JAMO_EXTENDED_B: | |
442 case UBLOCK_HANGUL_SYLLABLES: | |
443 case UBLOCK_HIRAGANA: | |
444 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS: | |
445 case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION: | |
446 case UBLOCK_KATAKANA: | |
447 case UBLOCK_LINEAR_B_IDEOGRAMS: | |
448 case UBLOCK_TANGUT: | |
449 case UBLOCK_TANGUT_COMPONENTS: | |
450 (*skipIndexes)[index] = true; | |
451 hasAnySkip = true; | |
452 break; | |
453 default: | |
454 break; | |
455 } | |
456 } | |
457 if (!hasAnySkip) | |
458 return nullptr; | |
459 return skipIndexes; | |
460 } | |
461 | |
389 static int getInterceptsFromBloberizer(const GlyphBuffer& glyphBuffer, | 462 static int getInterceptsFromBloberizer(const GlyphBuffer& glyphBuffer, |
390 const Font* font, | 463 const Font* font, |
391 const SkPaint& paint, | 464 const SkPaint& paint, |
392 float deviceScaleFactor, | 465 float deviceScaleFactor, |
393 const std::tuple<float, float>& bounds, | 466 const std::tuple<float, float>& bounds, |
467 const Vector<bool>* skipGlyphs, | |
394 SkScalar* interceptsBuffer) { | 468 SkScalar* interceptsBuffer) { |
395 SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)}; | 469 SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)}; |
396 GlyphBufferBloberizer bloberizer(glyphBuffer, font, deviceScaleFactor); | 470 GlyphBufferBloberizer bloberizer(glyphBuffer, font, deviceScaleFactor); |
471 bloberizer.setSkipGlyphs(skipGlyphs); | |
397 std::pair<sk_sp<SkTextBlob>, BlobRotation> blob; | 472 std::pair<sk_sp<SkTextBlob>, BlobRotation> blob; |
398 | 473 |
399 int numIntervals = 0; | 474 int numIntervals = 0; |
400 while (!bloberizer.done()) { | 475 while (!bloberizer.done()) { |
401 blob = bloberizer.next(); | 476 blob = bloberizer.next(); |
402 DCHECK(blob.first); | 477 DCHECK(blob.first); |
403 | 478 |
404 // GlyphBufferBloberizer splits for a new blob rotation, but does not split | 479 // GlyphBufferBloberizer splits for a new blob rotation, but does not split |
405 // for a change in font. A TextBlob can contain runs with differing fonts | 480 // for a change in font. A TextBlob can contain runs with differing fonts |
406 // and the getTextBlobIntercepts method handles multiple fonts for us. For | 481 // and the getTextBlobIntercepts method handles multiple fonts for us. For |
(...skipping 25 matching lines...) Expand all Loading... | |
432 if (!numIntervals) | 507 if (!numIntervals) |
433 return; | 508 return; |
434 DCHECK_EQ(numIntervals % 2, 0); | 509 DCHECK_EQ(numIntervals % 2, 0); |
435 intercepts.resize(numIntervals / 2); | 510 intercepts.resize(numIntervals / 2); |
436 paint.getTextBlobIntercepts(runInfo.cachedTextBlob->get(), boundsArray, | 511 paint.getTextBlobIntercepts(runInfo.cachedTextBlob->get(), boundsArray, |
437 reinterpret_cast<SkScalar*>(intercepts.data())); | 512 reinterpret_cast<SkScalar*>(intercepts.data())); |
438 return; | 513 return; |
439 } | 514 } |
440 | 515 |
441 GlyphBuffer glyphBuffer; | 516 GlyphBuffer glyphBuffer; |
442 buildGlyphBuffer(runInfo, glyphBuffer); | 517 std::unique_ptr<Vector<bool>> skipGlyphs; |
518 if (runInfo.run.is8Bit()) { | |
519 buildGlyphBuffer(runInfo, glyphBuffer); | |
520 } else { | |
521 glyphBuffer.saveCharacterIndexes(); | |
522 buildGlyphBuffer(runInfo, glyphBuffer); | |
523 skipGlyphs = glyphsToSkipIntercepts(runInfo.run, glyphBuffer); | |
524 } | |
443 | 525 |
444 // Get the number of intervals, without copying the actual values by | 526 // Get the number of intervals, without copying the actual values by |
445 // specifying nullptr for the buffer, following the Skia allocation model for | 527 // specifying nullptr for the buffer, following the Skia allocation model for |
446 // retrieving text intercepts. | 528 // retrieving text intercepts. |
447 int numIntervals = getInterceptsFromBloberizer( | 529 int numIntervals = |
448 glyphBuffer, this, paint, deviceScaleFactor, bounds, nullptr); | 530 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor, |
531 bounds, skipGlyphs.get(), nullptr); | |
449 if (!numIntervals) | 532 if (!numIntervals) |
450 return; | 533 return; |
451 DCHECK_EQ(numIntervals % 2, 0); | 534 DCHECK_EQ(numIntervals % 2, 0); |
452 intercepts.resize(numIntervals / 2); | 535 intercepts.resize(numIntervals / 2); |
453 | 536 |
454 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor, | 537 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor, |
455 bounds, | 538 bounds, skipGlyphs.get(), |
456 reinterpret_cast<SkScalar*>(intercepts.data())); | 539 reinterpret_cast<SkScalar*>(intercepts.data())); |
457 } | 540 } |
458 | 541 |
459 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) { | 542 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) { |
460 // Using roundf() rather than ceilf() for the right edge as a compromise to | 543 // Using roundf() rather than ceilf() for the right edge as a compromise to |
461 // ensure correct caret positioning. | 544 // ensure correct caret positioning. |
462 float roundedX = roundf(rect.x()); | 545 float roundedX = roundf(rect.x()); |
463 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), | 546 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), |
464 rect.height()); | 547 rect.height()); |
465 } | 548 } |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
620 | 703 |
621 bool Font::loadingCustomFonts() const { | 704 bool Font::loadingCustomFonts() const { |
622 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); | 705 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); |
623 } | 706 } |
624 | 707 |
625 bool Font::isFallbackValid() const { | 708 bool Font::isFallbackValid() const { |
626 return !m_fontFallbackList || m_fontFallbackList->isValid(); | 709 return !m_fontFallbackList || m_fontFallbackList->isValid(); |
627 } | 710 } |
628 | 711 |
629 } // namespace blink | 712 } // namespace blink |
OLD | NEW |