| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright (C) 2015 Google Inc. All rights reserved. | 2  * Copyright (C) 2015 Google Inc. All rights reserved. | 
| 3  * | 3  * | 
| 4  * Redistribution and use in source and binary forms, with or without | 4  * Redistribution and use in source and binary forms, with or without | 
| 5  * modification, are permitted provided that the following conditions | 5  * modification, are permitted provided that the following conditions | 
| 6  * are met: | 6  * are met: | 
| 7  * 1. Redistributions of source code must retain the above copyright | 7  * 1. Redistributions of source code must retain the above copyright | 
| 8  *    notice, this list of conditions and the following disclaimer. | 8  *    notice, this list of conditions and the following disclaimer. | 
| 9  * 2. Redistributions in binary form must reproduce the above copyright | 9  * 2. Redistributions in binary form must reproduce the above copyright | 
| 10  *    notice, this list of conditions and the following disclaimer in the | 10  *    notice, this list of conditions and the following disclaimer in the | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 31 #include "platform/fonts/shaping/HarfBuzzShaper.h" | 31 #include "platform/fonts/shaping/HarfBuzzShaper.h" | 
| 32 #include "platform/fonts/shaping/ShapeCache.h" | 32 #include "platform/fonts/shaping/ShapeCache.h" | 
| 33 #include "wtf/text/CharacterNames.h" | 33 #include "wtf/text/CharacterNames.h" | 
| 34 | 34 | 
| 35 namespace blink { | 35 namespace blink { | 
| 36 | 36 | 
| 37 class CachingWordShapeIterator { | 37 class CachingWordShapeIterator { | 
| 38 public: | 38 public: | 
| 39     CachingWordShapeIterator(ShapeCache* cache, const TextRun& run, | 39     CachingWordShapeIterator(ShapeCache* cache, const TextRun& run, | 
| 40         const Font* font) | 40         const Font* font) | 
| 41         : m_shapeCache(cache), m_textRun(run), m_font(font), m_startIndex(0) | 41         : m_shapeCache(cache), m_textRun(run), m_font(font) | 
|  | 42         , m_widthSoFar(0), m_startIndex(0) | 
| 42     { | 43     { | 
| 43         ASSERT(font); | 44         ASSERT(font); | 
| 44         const FontDescription& fontDescription = font->fontDescription(); | 45         const FontDescription& fontDescription = font->fontDescription(); | 
| 45 | 46 | 
| 46         // Word and letter spacing can change the width of a word, as can tabs | 47         // Word and letter spacing can change the width of a word, as can tabs | 
| 47         // as we segment solely based on on space characters. | 48         // as we segment solely based on on space characters. | 
| 48         // If expansion is used (for justified text) the spacing between words | 49         // If expansion is used (for justified text) the spacing between words | 
| 49         // change and thus we need to shape the entire run. | 50         // change and thus we need to shape the entire run. | 
| 50         m_wordResultCachable = !fontDescription.wordSpacing() | 51         m_wordResultCachable = !fontDescription.wordSpacing() | 
| 51             && !fontDescription.letterSpacing() && !run.allowTabs() | 52             && !fontDescription.letterSpacing() | 
| 52             && m_textRun.expansion() == 0.0f; | 53             && m_textRun.expansion() == 0.0f; | 
| 53 | 54 | 
| 54         // Shaping word by word is faster as each word is cached. If we cannot | 55         // Shaping word by word is faster as each word is cached. If we cannot | 
| 55         // use the cache or if the font doesn't support word by word shaping | 56         // use the cache or if the font doesn't support word by word shaping | 
| 56         // fall back on shaping the entire run. | 57         // fall back on shaping the entire run. | 
| 57         m_shapeByWord = m_wordResultCachable && m_font->canShapeWordByWord(); | 58         m_shapeByWord = m_wordResultCachable && m_font->canShapeWordByWord(); | 
| 58     } | 59     } | 
| 59 | 60 | 
| 60     bool next(RefPtr<ShapeResult>* wordResult) | 61     bool next(RefPtr<ShapeResult>* wordResult) | 
| 61     { | 62     { | 
|  | 63         if (UNLIKELY(m_textRun.allowTabs())) | 
|  | 64             return nextForAllowTabs(wordResult); | 
|  | 65 | 
| 62         if (!m_shapeByWord) { | 66         if (!m_shapeByWord) { | 
| 63             if (m_startIndex) | 67             if (m_startIndex) | 
| 64                 return false; | 68                 return false; | 
| 65             *wordResult = shapeWord(m_textRun, m_font); | 69             *wordResult = shapeWord(m_textRun, m_font); | 
| 66             m_startIndex = 1; | 70             m_startIndex = 1; | 
| 67             return *wordResult; | 71             return *wordResult; | 
| 68         } | 72         } | 
| 69 | 73 | 
| 70         unsigned length = m_textRun.length(); | 74         return nextWord(wordResult); | 
| 71         if (m_startIndex < length) { |  | 
| 72             if (m_textRun[m_startIndex] == spaceCharacter) { |  | 
| 73                 TextRun wordRun = m_textRun.subRun(m_startIndex, 1); |  | 
| 74                 *wordResult = shapeWord(wordRun, m_font); |  | 
| 75                 m_startIndex++; |  | 
| 76                 return true; |  | 
| 77             } |  | 
| 78 |  | 
| 79             for (unsigned i = m_startIndex; ; i++) { |  | 
| 80                 if (i == length || m_textRun[i] == spaceCharacter) { |  | 
| 81                     TextRun wordRun = m_textRun.subRun(m_startIndex, |  | 
| 82                         i - m_startIndex); |  | 
| 83                     *wordResult = shapeWord(wordRun, m_font); |  | 
| 84                     m_startIndex = i; |  | 
| 85                     return true; |  | 
| 86                 } |  | 
| 87             } |  | 
| 88         } |  | 
| 89         return false; |  | 
| 90     } | 75     } | 
| 91 | 76 | 
| 92 private: | 77 private: | 
| 93     PassRefPtr<ShapeResult> shapeWord(const TextRun& wordRun, const Font* font) | 78     PassRefPtr<ShapeResult> shapeWord(const TextRun& wordRun, const Font* font) | 
| 94     { | 79     { | 
| 95         ShapeCacheEntry* cacheEntry = m_wordResultCachable | 80         ShapeCacheEntry* cacheEntry = m_wordResultCachable | 
| 96             ? m_shapeCache->add(wordRun, ShapeCacheEntry()) | 81             ? m_shapeCache->add(wordRun, ShapeCacheEntry()) | 
| 97             : nullptr; | 82             : nullptr; | 
| 98         if (cacheEntry && cacheEntry->m_shapeResult) | 83         if (cacheEntry && cacheEntry->m_shapeResult) | 
| 99             return cacheEntry->m_shapeResult; | 84             return cacheEntry->m_shapeResult; | 
| 100 | 85 | 
| 101         HarfBuzzShaper shaper(font, wordRun); | 86         HarfBuzzShaper shaper(font, wordRun); | 
| 102         RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); | 87         RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); | 
| 103         if (!shapeResult) | 88         if (!shapeResult) | 
| 104             return nullptr; | 89             return nullptr; | 
| 105 | 90 | 
| 106         if (cacheEntry) | 91         if (cacheEntry) | 
| 107             cacheEntry->m_shapeResult = shapeResult; | 92             cacheEntry->m_shapeResult = shapeResult; | 
| 108 | 93 | 
| 109         return shapeResult.release(); | 94         return shapeResult.release(); | 
| 110     } | 95     } | 
| 111 | 96 | 
|  | 97     bool nextWord(RefPtr<ShapeResult>* wordResult) | 
|  | 98     { | 
|  | 99         unsigned length = m_textRun.length(); | 
|  | 100         if (m_startIndex < length) { | 
|  | 101             if (m_textRun[m_startIndex] == spaceCharacter | 
|  | 102                 || m_textRun[m_startIndex] == tabulationCharacter) { | 
|  | 103                 TextRun wordRun = m_textRun.subRun(m_startIndex, 1); | 
|  | 104                 *wordResult = shapeWord(wordRun, m_font); | 
|  | 105                 m_startIndex++; | 
|  | 106                 return *wordResult; | 
|  | 107             } | 
|  | 108 | 
|  | 109             return nextUntilCharacterOrTab(wordResult, spaceCharacter); | 
|  | 110         } | 
|  | 111         return false; | 
|  | 112     } | 
|  | 113 | 
|  | 114     bool nextUntilCharacterOrTab(RefPtr<ShapeResult>* wordResult, UChar delimite
     r) | 
|  | 115     { | 
|  | 116         unsigned length = m_textRun.length(); | 
|  | 117         ASSERT(m_startIndex < length); | 
|  | 118         for (unsigned i = m_startIndex + 1; ; i++) { | 
|  | 119             if (i == length || m_textRun[i] == delimiter | 
|  | 120                 || m_textRun[i] == tabulationCharacter) { | 
|  | 121                 TextRun wordRun = m_textRun.subRun(m_startIndex, | 
|  | 122                     i - m_startIndex); | 
|  | 123                 m_startIndex = i; | 
|  | 124                 *wordResult = shapeWord(wordRun, m_font); | 
|  | 125                 return *wordResult; | 
|  | 126             } | 
|  | 127         } | 
|  | 128     } | 
|  | 129 | 
|  | 130     bool nextForAllowTabs(RefPtr<ShapeResult>* wordResult) | 
|  | 131     { | 
|  | 132         unsigned length = m_textRun.length(); | 
|  | 133         if (m_startIndex >= length) | 
|  | 134             return false; | 
|  | 135 | 
|  | 136         if (UNLIKELY(m_textRun[m_startIndex] == tabulationCharacter)) { | 
|  | 137             for (unsigned i = m_startIndex + 1; ; i++) { | 
|  | 138                 if (i == length || m_textRun[i] != tabulationCharacter) { | 
|  | 139                     *wordResult = ShapeResult::createForTabulationCharacters( | 
|  | 140                         m_font, m_textRun, m_widthSoFar, i - m_startIndex); | 
|  | 141                     m_startIndex = i; | 
|  | 142                     break; | 
|  | 143                 } | 
|  | 144             } | 
|  | 145         } else if (!m_shapeByWord) { | 
|  | 146             if (!nextUntilCharacterOrTab(wordResult, 0)) | 
|  | 147                 return false; | 
|  | 148         } else { | 
|  | 149             if (!nextWord(wordResult)) | 
|  | 150                 return false; | 
|  | 151         } | 
|  | 152         if (!*wordResult) | 
|  | 153             return false; | 
|  | 154         m_widthSoFar += (*wordResult)->width(); | 
|  | 155         return true; | 
|  | 156     } | 
|  | 157 | 
| 112     ShapeCache* m_shapeCache; | 158     ShapeCache* m_shapeCache; | 
| 113     const TextRun& m_textRun; | 159     const TextRun& m_textRun; | 
| 114     const Font* m_font; | 160     const Font* m_font; | 
|  | 161     float m_widthSoFar; // Used only when allowTabs() | 
| 115     unsigned m_startIndex : 30; | 162     unsigned m_startIndex : 30; | 
| 116     unsigned m_wordResultCachable : 1; | 163     unsigned m_wordResultCachable : 1; | 
| 117     unsigned m_shapeByWord : 1; | 164     unsigned m_shapeByWord : 1; | 
| 118 }; | 165 }; | 
| 119 | 166 | 
| 120 } // namespace blink | 167 } // namespace blink | 
| 121 | 168 | 
| 122 #endif // CachingWordShapeIterator_h | 169 #endif // CachingWordShapeIterator_h | 
| OLD | NEW | 
|---|