Index: third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h |
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h |
index b851ac2464f7fd0bd5c7f15a3e810e83765f8ece..990acc661bd63810a4b19b6150b98c51afebae1d 100644 |
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h |
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h |
@@ -36,6 +36,7 @@ |
#include "platform/geometry/FloatPoint.h" |
#include "platform/geometry/FloatRect.h" |
#include "platform/text/TextRun.h" |
+#include "wtf/Deque.h" |
#include "wtf/HashSet.h" |
#include "wtf/OwnPtr.h" |
#include "wtf/PassOwnPtr.h" |
@@ -114,31 +115,131 @@ private: |
friend class HarfBuzzShaper; |
}; |
+ |
+// Shaping text runs is split into several stages: Run segmentation, shaping the |
+// initial segment, identify shaped and non-shaped sequences of the shaping |
+// result, and processing sub-runs by trying to shape them with a fallback font |
+// until the last resort font is reached. |
+// |
+// Going through one example to illustrate the process: The following is a run of |
+// vertical text to be shaped. After run segmentation in RunSegmenter it is split |
+// into 4 segments. The segments indicated by the segementation results showing |
+// the script, orientation information and small caps handling of the individual |
+// segment. The Japanese text at the beginning has script "Hiragana", does not |
+// need rotation when laid out vertically and does not need uppercasing when |
+// small caps is requested. |
+// |
+// 0 い |
+// 1 ろ |
+// 2 は USCRIPT_HIRAGANA, |
+// OrientationIterator::OrientationKeep, |
+// SmallCapsIterator::SmallCapsSameCase |
+// |
+// 3 a |
+// 4 ̄ (Combining Macron) |
+// 5 a |
+// 6 A USCRIPT_LATIN, |
+// OrientationIterator::OrientationRotateSideways, |
+// SmallCapsIterator::SmallCapsUppercaseNeeded |
+// |
+// 7 い |
+// 8 ろ |
+// 9 は USCRIPT_HIRAGANA, |
+// OrientationIterator::OrientationKeep, |
+// SmallCapsIterator::SmallCapsSameCase |
+// |
+// |
+// Let's assume the CSS for this text run is as follows: |
+// font-family: "Heiti SC", Tinos, sans-serif; |
+// where Tinos is a web font, defined as a composite font, with two sub ranges, |
+// one for Latin U+00-U+FF and one unrestricted unicode-range. |
+// |
+// FontFallbackIterator provides the shaper with Heiti SC, then Tinos of the |
+// restricted unicode-range, then the unrestricted full unicode-range Tinos, then |
+// a system sans-serif. |
+// |
+// The initial segment 0-2 to the shaper, together with the segmentation |
+// properties and the initial Heiti SC font. Characters 0-2 are shaped |
+// successfully with Heiti SC. The next segment, 3-5 is passed to the shaper. The |
+// shaper attempts to shape it with Heiti SC, which fails for the Combining |
+// Macron. So the shaping result for this segment would look similar to this. |
+// |
+// Glyphpos: 0 1 2 3 |
+// Cluster: 0 0 2 3 |
+// Glyph: a x a A (where x is .notdef) |
+// |
+// Now in the extractShapeResults() step we notice that there is more work to do, |
+// since Heiti SC does not have a glyph for the Combining Macron combined with an |
+// a. So, this cluster together with a Todo item for switching to the next font |
+// is put into HolesQueue. |
+// |
+// After shaping the initial segment, the remaining items in the HolesQueue are |
+// processed, picking them from the head of the queue. So, first, the next font |
+// is requested from the FontFallbackIterator. In this case, Tinos (for the range |
+// U+00-U+FF) comes back. Shaping using this font, assuming it is subsetted, |
+// fails again since there is no combining mark available. This triggers |
+// requesting yet another font. This time, the Tinos font for the full |
+// range. With this, shaping succeeds with the following HarfBuzz result: |
+// |
+// Glyphpos 0 1 2 3 |
+// Cluster: 0 0 2 3 |
+// Glyph: a ̄ a A (with glyph coordinates placing the ̄ above the first a) |
+// |
+// Now this sub run is successfully processed and can be appended to |
+// ShapeResult. A new ShapeResult::RunInfo is created. The logic in |
+// insertRunIntoShapeResult then takes care of merging the shape result into |
+// the right position the vector of RunInfos in ShapeResult. |
+// |
+// Shaping then continues analogously for the remaining Hiragana Japanese |
+// sub-run, and the result is inserted into ShapeResult as well. |
class PLATFORM_EXPORT HarfBuzzShaper final : public Shaper { |
public: |
HarfBuzzShaper(const Font*, const TextRun&); |
PassRefPtr<ShapeResult> shapeResult(); |
~HarfBuzzShaper() { } |
-private: |
- struct HarfBuzzRun { |
- const SimpleFontData* m_fontData; |
+ enum HolesQueueItemAction { |
+ HolesQueueNextFont, |
+ HolesQueueRange |
+ }; |
+ |
+ struct HolesQueueItem { |
+ HolesQueueItemAction m_action; |
unsigned m_startIndex; |
- size_t m_numCharacters; |
- hb_direction_t m_direction; |
- hb_script_t m_script; |
+ unsigned m_numCharacters; |
+ HolesQueueItem(HolesQueueItemAction action, unsigned start, unsigned num) |
+ : m_action(action) |
+ , m_startIndex(start) |
+ , m_numCharacters(num) {}; |
}; |
+private: |
float nextExpansionPerOpportunity(); |
void setExpansion(float); |
void setFontFeatures(); |
- bool createHarfBuzzRuns(); |
- bool createHarfBuzzRunsForSingleCharacter(); |
- PassRefPtr<ShapeResult> shapeHarfBuzzRuns(); |
- void shapeResult(ShapeResult*, unsigned, const HarfBuzzRun*, hb_buffer_t*); |
+ void appendToHolesQueue(HolesQueueItemAction, |
+ unsigned startIndex, |
+ unsigned numCharacters); |
+ inline bool shapeRange(hb_buffer_t* harfBuzzBuffer, |
+ unsigned startIndex, |
+ unsigned numCharacters, |
+ const SimpleFontData* currentFont, |
+ unsigned currentFontRangeFrom, |
+ unsigned currentFontRangeTo, |
+ UScriptCode currentRunScript, |
+ hb_language_t); |
+ bool extractShapeResults(hb_buffer_t* harfBuzzBuffer, |
+ ShapeResult*, |
+ bool& fontCycleQueued, |
+ const HolesQueueItem& currentQueueItem, |
+ const SimpleFontData* currentFont, |
+ UScriptCode currentRunScript, |
+ bool isLastResort); |
+ bool collectFallbackHintChars(Vector<UChar32>& hint, bool needsList); |
+ |
+ void insertRunIntoShapeResult(ShapeResult*, PassOwnPtr<ShapeResult::RunInfo> runToInsert, unsigned startGlyph, unsigned numGlyphs, int, hb_buffer_t*); |
float adjustSpacing(ShapeResult::RunInfo*, size_t glyphIndex, unsigned currentCharacterIndex, float& offsetX, float& totalAdvance); |
- void addHarfBuzzRun(unsigned startCharacter, unsigned endCharacter, const SimpleFontData*, UScriptCode); |
OwnPtr<UChar[]> m_normalizedBuffer; |
unsigned m_normalizedBufferLength; |
@@ -148,9 +249,10 @@ private: |
unsigned m_expansionOpportunityCount; |
Vector<hb_feature_t, 4> m_features; |
- Vector<HarfBuzzRun, 16> m_harfBuzzRuns; |
+ Deque<HolesQueueItem> m_holesQueue; |
}; |
+ |
} // namespace blink |
#endif // HarfBuzzShaper_h |