Chromium Code Reviews| 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 |