1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file. 4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/render_text_harfbuzz.h" 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <limits> 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <map> 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/i18n/bidi_line_iterator.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/i18n/break_iterator.h" 12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/i18n/char_iterator.h" 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/lazy_instance.h" 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/harfbuzz-ng/src/hb.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/icu/source/common/unicode/ubidi.h" 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h" 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/skia/include/core/SkTypeface.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/canvas.h" 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gfx/font_fallback.h" 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/gfx/font_render_params.h" 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/utf16_indexing.h" 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_WIN) 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gfx/font_fallback_win.h" 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace gfx { 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace { 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Text length limit. Longer strings are slow and not fully tested. 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst size_t kMaxTextLength = 10000; 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// The maximum number of scripts a Unicode character can belong to. This value 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// is arbitrarily chosen to be a good limit because it is unlikely for a single 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// character to belong to more scripts. 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const size_t kMaxScripts = 5; 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Maps from code points to glyph indices in a font. 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)typedef std::map<uint32_t, uint16_t> GlyphCache; 41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Font data provider for HarfBuzz using Skia. Copied from Blink. 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// TODO(ckocagil): Eliminate the duplication. http://crbug.com/368375 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)struct FontData { 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {} 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint paint_; 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GlyphCache* glyph_cache_; 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) { 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SkScalarToFixed(value); 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Deletes the object at the given pointer after casting it to the given type. 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)template<typename Type> 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DeleteByType(void* data) { 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Type* typed_data = reinterpret_cast<Type*>(data); 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) delete typed_data; 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)template<typename Type> 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DeleteArrayByType(void* data) { 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Type* typed_data = reinterpret_cast<Type*>(data); 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) delete[] typed_data; 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Outputs the |width| and |extents| of the glyph with index |codepoint| in 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// |paint|'s font. 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void GetGlyphWidthAndExtents(SkPaint* paint, 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t codepoint, 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_position_t* width, 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_glyph_extents_t* extents) { 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_LE(codepoint, 0xFFFFU); 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar sk_width; 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkRect sk_bounds; 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) uint16_t glyph = codepoint; 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds); 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (width) 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *width = SkiaScalarToHarfBuzzPosition(sk_width); 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (extents) { 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // y-grows-up. 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extents->x_bearing = SkiaScalarToHarfBuzzPosition(sk_bounds.fLeft); 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extents->y_bearing = SkiaScalarToHarfBuzzPosition(-sk_bounds.fTop); 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extents->width = SkiaScalarToHarfBuzzPosition(sk_bounds.width()); 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extents->height = SkiaScalarToHarfBuzzPosition(-sk_bounds.height()); 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Writes the |glyph| index for the given |unicode| code point. Returns whether 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// the glyph exists, i.e. it is not a missing glyph. 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_bool_t GetGlyph(hb_font_t* font, 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* data, 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t unicode, 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t variation_selector, 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t* glyph, 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* user_data) { 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData* font_data = reinterpret_cast<FontData*>(data); 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GlyphCache* cache = font_data->glyph_cache_; 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool exists = cache->count(unicode) != 0; 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!exists) { 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint* paint = &font_data->paint_; 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]); 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *glyph = (*cache)[unicode]; 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return !!*glyph; 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returns the horizontal advance value of the |glyph|. 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font, 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* data, 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t glyph, 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* user_data) { 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData* font_data = reinterpret_cast<FontData*>(data); 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_position_t advance = 0; 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetGlyphWidthAndExtents(&font_data->paint_, glyph, &advance, 0); 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return advance; 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_bool_t GetGlyphHorizontalOrigin(hb_font_t* font, 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* data, 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t glyph, 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_position_t* x, 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_position_t* y, 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* user_data) { 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Just return true, like the HarfBuzz-FreeType implementation. 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_position_t GetGlyphKerning(FontData* font_data, 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t first_glyph, 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t second_glyph) { 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkTypeface* typeface = font_data->paint_.getTypeface(); 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const uint16_t glyphs[2] = { static_cast<uint16_t>(first_glyph), 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) static_cast<uint16_t>(second_glyph) }; 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int32_t kerning_adjustments[1] = { 0 }; 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments)) 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar size = font_data->paint_.getTextSize(); 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SkiaScalarToHarfBuzzPosition( 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalarMulDiv(SkIntToScalar(kerning_adjustments[0]), size, upm)); 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_position_t GetGlyphHorizontalKerning(hb_font_t* font, 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* data, 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t left_glyph, 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t right_glyph, 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* user_data) { 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData* font_data = reinterpret_cast<FontData*>(data); 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (font_data->paint_.isVerticalText()) { 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We don't support cross-stream kerning. 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return GetGlyphKerning(font_data, left_glyph, right_glyph); 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_position_t GetGlyphVerticalKerning(hb_font_t* font, 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* data, 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t top_glyph, 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t bottom_glyph, 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* user_data) { 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData* font_data = reinterpret_cast<FontData*>(data); 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!font_data->paint_.isVerticalText()) { 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We don't support cross-stream kerning. 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return GetGlyphKerning(font_data, top_glyph, bottom_glyph); 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Writes the |extents| of |glyph|. 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_bool_t GetGlyphExtents(hb_font_t* font, 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* data, 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_codepoint_t glyph, 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_glyph_extents_t* extents, 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void* user_data) { 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData* font_data = reinterpret_cast<FontData*>(data); 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetGlyphWidthAndExtents(&font_data->paint_, glyph, 0, extents); 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class FontFuncs { 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public: 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) FontFuncs() : font_funcs_(hb_font_funcs_create()) { 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hb_font_funcs_set_glyph_func(font_funcs_, GetGlyph, 0, 0); 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_funcs_set_glyph_h_advance_func( 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) font_funcs_, GetGlyphHorizontalAdvance, 0, 0); 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_funcs_set_glyph_h_kerning_func( 201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) font_funcs_, GetGlyphHorizontalKerning, 0, 0); 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_funcs_set_glyph_h_origin_func( 203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) font_funcs_, GetGlyphHorizontalOrigin, 0, 0); 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_funcs_set_glyph_v_kerning_func( 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) font_funcs_, GetGlyphVerticalKerning, 0, 0); 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_funcs_set_glyph_extents_func( 207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) font_funcs_, GetGlyphExtents, 0, 0); 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hb_font_funcs_make_immutable(font_funcs_); 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ~FontFuncs() { 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hb_font_funcs_destroy(font_funcs_); 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hb_font_funcs_t* get() { return font_funcs_; } 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private: 218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hb_font_funcs_t* font_funcs_; 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(FontFuncs); 221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)base::LazyInstance<FontFuncs>::Leaky g_font_funcs = LAZY_INSTANCE_INITIALIZER; 224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returns the raw data of the font table |tag|. 226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)hb_blob_t* GetFontTable(hb_face_t* face, hb_tag_t tag, void* user_data) { 227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkTypeface* typeface = reinterpret_cast<SkTypeface*>(user_data); 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const size_t table_size = typeface->getTableSize(tag); 230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!table_size) 231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<char[]> buffer(new char[table_size]); 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!buffer) 235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t actual_size = typeface->getTableData(tag, 0, table_size, buffer.get()); 237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (table_size != actual_size) 238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) char* buffer_raw = buffer.release(); 241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return hb_blob_create(buffer_raw, table_size, HB_MEMORY_MODE_WRITABLE, 242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) buffer_raw, DeleteArrayByType<char>); 243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void UnrefSkTypeface(void* data) { 246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkTypeface* skia_face = reinterpret_cast<SkTypeface*>(data); 247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkSafeUnref(skia_face); 248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Wrapper class for a HarfBuzz face created from a given Skia face. 2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class HarfBuzzFace { 2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) public: 2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HarfBuzzFace() : face_(NULL) {} 2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ~HarfBuzzFace() { 2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (face_) 2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) hb_face_destroy(face_); 2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void Init(SkTypeface* skia_face) { 2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SkSafeRef(skia_face); 2626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) face_ = hb_face_create_for_tables(GetFontTable, skia_face, UnrefSkTypeface); 2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DCHECK(face_); 2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) hb_face_t* get() { 2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return face_; 2686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private: 2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) hb_face_t* face_; 2726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Creates a HarfBuzz font from the given Skia face and text size. 2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccihb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face, 2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int text_size, 2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const FontRenderParams& params, 2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool background_is_transparent) { 2796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) typedef std::pair<HarfBuzzFace, GlyphCache> FaceCache; 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache? 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) static std::map<SkFontID, FaceCache> face_caches; 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FaceCache* face_cache = &face_caches[skia_face->uniqueID()]; 2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (face_cache->first.get() == NULL) 2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) face_cache->first.Init(skia_face); 287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 2886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) hb_font_t* harfbuzz_font = hb_font_create(face_cache->first.get()); 289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const int scale = SkScalarToFixed(text_size); 290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch hb_font_set_scale(harfbuzz_font, scale, scale); 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FontData* hb_font_data = new FontData(&face_cache->second); 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_data->paint_.setTypeface(skia_face); 293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_data->paint_.setTextSize(text_size); 2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // TODO(ckocagil): Do we need to update these params later? 2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci internal::ApplyRenderParams(params, background_is_transparent, 2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &hb_font_data->paint_); 297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), hb_font_data, 298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DeleteByType<FontData>); 299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_make_immutable(harfbuzz_font); 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return harfbuzz_font; 301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returns true if characters of |block_code| may trigger font fallback. 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool IsUnusualBlockCode(UBlockCode block_code) { 305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return block_code == UBLOCK_GEOMETRIC_SHAPES || 306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) block_code == UBLOCK_MISCELLANEOUS_SYMBOLS; 307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool IsBracket(UChar32 character) { 3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static const char kBrackets[] = { '(', ')', '{', '}', '<', '>', }; 3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static const char* kBracketsEnd = kBrackets + arraysize(kBrackets); 3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return std::find(kBrackets, kBracketsEnd, character) != kBracketsEnd; 3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Returns the boundary between a special and a regular character. Special 3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// characters are brackets or characters that satisfy |IsUnusualBlockCode|. 3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccisize_t FindRunBreakingCharacter(const base::string16& text, 3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t run_start, 3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t run_break) { 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const int32 run_length = static_cast<int32>(run_break - run_start); 3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::i18n::UTF16CharIterator iter(text.c_str() + run_start, run_length); 3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const UChar32 first_char = iter.get(); 3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const UBlockCode first_block = ublock_getCode(first_char); 3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const bool first_block_unusual = IsUnusualBlockCode(first_block); 3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const bool first_bracket = IsBracket(first_char); 3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (iter.Advance() && iter.array_pos() < run_length) { 3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const UChar32 current_char = iter.get(); 3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const UBlockCode current_block = ublock_getCode(current_char); 3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const bool block_break = current_block != first_block && 3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (first_block_unusual || IsUnusualBlockCode(current_block)); 3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (block_break || first_bracket != IsBracket(current_char)) 333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return run_start + iter.array_pos(); 334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return run_break; 336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// If the given scripts match, returns the one that isn't USCRIPT_COMMON or 339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns 340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// USCRIPT_INVALID_CODE. 341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) { 342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (first == second || 343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) { 344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return first; 345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (first > USCRIPT_INVALID_CODE && first <= USCRIPT_INHERITED) 347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return second; 348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return USCRIPT_INVALID_CODE; 349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Writes the script and the script extensions of the character with the 352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Unicode |codepoint|. Returns the number of written scripts. 353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int GetScriptExtensions(UChar32 codepoint, UScriptCode* scripts) { 354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UErrorCode icu_error = U_ZERO_ERROR; 355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // ICU documentation incorrectly states that the result of 356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // |uscript_getScriptExtensions| will contain the regular script property. 357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Write the character's script property to the first element. 358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scripts[0] = uscript_getScript(codepoint, &icu_error); 359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (U_FAILURE(icu_error)) 360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return 0; 361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Fill the rest of |scripts| with the extensions. 362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int count = uscript_getScriptExtensions(codepoint, scripts + 1, 363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) kMaxScripts - 1, &icu_error); 364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (U_FAILURE(icu_error)) 365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) count = 0; 366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return count + 1; 367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Intersects the script extensions set of |codepoint| with |result| and writes 370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// to |result|, reading and updating |result_size|. 371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ScriptSetIntersect(UChar32 codepoint, 372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UScriptCode* result, 373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t* result_size) { 374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE }; 375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int count = GetScriptExtensions(codepoint, scripts); 376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t out_size = 0; 378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < *result_size; ++i) { 380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (int j = 0; j < count; ++j) { 381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UScriptCode intersection = ScriptIntersect(result[i], scripts[j]); 382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (intersection != USCRIPT_INVALID_CODE) { 383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) result[out_size++] = intersection; 384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *result_size = out_size; 390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Find the longest sequence of characters from 0 and up to |length| that 393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// have at least one common UScriptCode value. Writes the common script value to 394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// |script| and returns the length of the sequence. Takes the characters' script 395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// extensions into account. http://www.unicode.org/reports/tr24/#ScriptX 396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// 397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Consider 3 characters with the script values {Kana}, {Hira, Kana}, {Kana}. 398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Without script extensions only the first script in each set would be taken 399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// into account, resulting in 3 runs where 1 would be enough. 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// TODO(ckocagil): Write a unit test for the case above. 401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int ScriptInterval(const base::string16& text, 402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t start, 403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t length, 404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UScriptCode* script) { 405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_GT(length, 0U); 406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE }; 408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::i18n::UTF16CharIterator char_iterator(text.c_str() + start, length); 410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t scripts_size = GetScriptExtensions(char_iterator.get(), scripts); 411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *script = scripts[0]; 412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) while (char_iterator.Advance()) { 414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size); 415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (scripts_size == 0U) 416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return char_iterator.array_pos(); 417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *script = scripts[0]; 418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return length; 421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// A port of hb_icu_script_to_script because harfbuzz on CrOS is built without 424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// hb-icu. See http://crbug.com/356929 425cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)inline hb_script_t ICUScriptToHBScript(UScriptCode script) { 426cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (script == USCRIPT_INVALID_CODE) 427cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return HB_SCRIPT_INVALID; 428cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return hb_script_from_string(uscript_getShortName(script), -1); 429cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 430cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Helper template function for |TextRunHarfBuzz::GetClusterAt()|. |Iterator| 4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// can be a forward or reverse iterator type depending on the text direction. 4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <class Iterator> 4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void GetClusterAtImpl(size_t pos, 4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range range, 4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Iterator elements_begin, 4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Iterator elements_end, 4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool reversed, 4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range* chars, 4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range* glyphs) { 4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Iterator element = std::upper_bound(elements_begin, elements_end, pos); 4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chars->set_end(element == elements_end ? range.end() : *element); 4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) glyphs->set_end(reversed ? elements_end - element : element - elements_begin); 4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(element != elements_begin); 4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (--element != elements_begin && *element == *(element - 1)); 4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chars->set_start(*element); 4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) glyphs->set_start( 4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) reversed ? elements_end - element : element - elements_begin); 4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (reversed) 4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *glyphs = Range(glyphs->end(), glyphs->start()); 4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(!chars->is_reversed()); 4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(!chars->is_empty()); 4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(!glyphs->is_reversed()); 4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(!glyphs->is_empty()); 4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 459cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace 460cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace internal { 462cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 463cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TextRunHarfBuzz::TextRunHarfBuzz() 4646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : width(0.0f), 4656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) preceding_run_widths(0.0f), 466cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) is_rtl(false), 467cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) level(0), 468cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) script(USCRIPT_INVALID_CODE), 469116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch glyph_count(static_cast<size_t>(-1)), 470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) font_size(0), 471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) font_style(0), 472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) strike(false), 473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) diagonal_strike(false), 474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) underline(false) {} 475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 476cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TextRunHarfBuzz::~TextRunHarfBuzz() {} 477cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void TextRunHarfBuzz::GetClusterAt(size_t pos, 4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range* chars, 4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range* glyphs) const { 4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(range.Contains(Range(pos, pos + 1))); 4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(chars); 4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(glyphs); 484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (glyph_count == 0) { 4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *chars = range; 4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *glyphs = Range(); 4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 489cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (is_rtl) { 4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(), 4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) true, chars, glyphs); 4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(), 4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) false, chars, glyphs); 499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 501f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Range TextRunHarfBuzz::CharRangeToGlyphRange(const Range& char_range) const { 502f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(range.Contains(char_range)); 503f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!char_range.is_reversed()); 504f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!char_range.is_empty()); 505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range start_glyphs; 5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range end_glyphs; 5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range temp_range; 5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetClusterAt(char_range.start(), &temp_range, &start_glyphs); 5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetClusterAt(char_range.end() - 1, &temp_range, &end_glyphs); 511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return is_rtl ? Range(end_glyphs.start(), start_glyphs.end()) : 5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range(start_glyphs.start(), end_glyphs.end()); 514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)size_t TextRunHarfBuzz::CountMissingGlyphs() const { 517cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) static const int kMissingGlyphId = 0; 5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t missing = 0; 5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < glyph_count; ++i) 5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; 5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return missing; 522cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Range TextRunHarfBuzz::GetGraphemeBounds( 5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::i18n::BreakIterator* grapheme_iterator, 5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t text_index) { 5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_LT(text_index, range.end()); 5286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // TODO(msw): Support floating point grapheme bounds. 5296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const int preceding_run_widths_int = SkScalarRoundToInt(preceding_run_widths); 5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (glyph_count == 0) 5316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return Range(preceding_run_widths_int, preceding_run_widths_int + width); 5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range chars; 5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range glyphs; 5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetClusterAt(text_index, &chars, &glyphs); 5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); 5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int cluster_end_x = glyphs.end() < glyph_count ? 5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SkScalarRoundToInt(positions[glyphs.end()].x()) : width; 5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // A cluster consists of a number of code points and corresponds to a number 5415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // of glyphs that should be drawn together. A cluster can contain multiple 5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // graphemes. In order to place the cursor at a grapheme boundary inside the 5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // cluster, we simply divide the cluster width by the number of graphemes. 5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (chars.length() > 1 && grapheme_iterator) { 5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int before = 0; 5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int total = 0; 5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = chars.start(); i < chars.end(); ++i) { 5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (grapheme_iterator->IsGraphemeBoundary(i)) { 5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (i < text_index) 5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++before; 5515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++total; 5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_GT(total, 0); 5555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (total > 1) { 5565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (is_rtl) 5575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) before = total - before - 1; 5585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_GE(before, 0); 5595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_LT(before, total); 5605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int cluster_width = cluster_end_x - cluster_begin_x; 5615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int grapheme_begin_x = cluster_begin_x + static_cast<int>(0.5f + 5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cluster_width * before / static_cast<float>(total)); 5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + 5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cluster_width * (before + 1) / static_cast<float>(total)); 5656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return Range(preceding_run_widths_int + grapheme_begin_x, 5666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) preceding_run_widths_int + grapheme_end_x); 5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 568cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return Range(preceding_run_widths_int + cluster_begin_x, 5716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) preceding_run_widths_int + cluster_end_x); 572cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 573cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 574cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace internal 575cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 576cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)RenderTextHarfBuzz::RenderTextHarfBuzz() 577cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : RenderText(), 5781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci needs_layout_(false) { 5791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci set_truncate_length(kMaxTextLength); 5801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 581cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 582cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)RenderTextHarfBuzz::~RenderTextHarfBuzz() {} 583cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 584cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Size RenderTextHarfBuzz::GetStringSize() { 5856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const SizeF size_f = GetStringSizeF(); 5866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return Size(std::ceil(size_f.width()), size_f.height()); 5876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 5886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 5896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)SizeF RenderTextHarfBuzz::GetStringSizeF() { 590cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EnsureLayout(); 591f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return lines()[0].size; 592cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 593cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 594cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { 595cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EnsureLayout(); 596cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 597cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int x = ToTextPoint(point).x(); 598cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int offset = 0; 599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t run_index = GetRunContainingXCoord(x, &offset); 600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (run_index >= runs_.size()) 601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); 602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const internal::TextRunHarfBuzz& run = *runs_[run_index]; 603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < run.glyph_count; ++i) { 605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkScalar end = 606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); 607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkScalar middle = (end + run.positions[i].x()) / 2; 608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 609cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (offset < middle) { 610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(LayoutIndexToTextIndex( 611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)), 612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD)); 613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (offset < end) { 615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(LayoutIndexToTextIndex( 616cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)), 617cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD)); 618cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 619cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 620cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return EdgeSelectionModel(CURSOR_RIGHT); 621cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 622cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() { 6241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci EnsureLayout(); 6251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::vector<RenderText::FontSpan> spans; 6271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < runs_.size(); ++i) { 6281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SkString family_name; 6291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci runs_[i]->skia_face->getFamilyName(&family_name); 6301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Font font(family_name.c_str(), runs_[i]->font_size); 6311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spans.push_back(RenderText::FontSpan(font, 6321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Range(LayoutIndexToTextIndex(runs_[i]->range.start()), 6331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LayoutIndexToTextIndex(runs_[i]->range.end())))); 6341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 6351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return spans; 637cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 638cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 6395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { 6405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EnsureLayout(); 6415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t run_index = 6425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); 6435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Return edge bounds if the index is invalid or beyond the layout text size. 6445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (run_index >= runs_.size()) 6455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Range(GetStringSize().width()); 6465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t layout_index = TextIndexToLayoutIndex(index); 6475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) internal::TextRunHarfBuzz* run = runs_[run_index]; 6485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range bounds = run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); 6495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return run->is_rtl ? Range(bounds.end(), bounds.start()) : bounds; 6505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 6515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 652cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int RenderTextHarfBuzz::GetLayoutTextBaseline() { 653cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EnsureLayout(); 654cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return lines()[0].baseline; 655cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 656cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 657cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( 658cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SelectionModel& selection, 659cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VisualCursorDirection direction) { 660cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!needs_layout_); 661cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) internal::TextRunHarfBuzz* run; 662cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t run_index = GetRunContainingCaret(selection); 663cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (run_index >= runs_.size()) { 664cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The cursor is not in any run: we're at the visual and logical edge. 665cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SelectionModel edge = EdgeSelectionModel(direction); 666cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (edge.caret_pos() == selection.caret_pos()) 667cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return edge; 668cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1; 669cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run = runs_[visual_to_logical_[visual_index]]; 670cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 671cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // If the cursor is moving within the current run, just move it by one 672cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // grapheme in the appropriate direction. 673cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run = runs_[run_index]; 674cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t caret = selection.caret_pos(); 675cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); 676cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (forward_motion) { 677cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (caret < LayoutIndexToTextIndex(run->range.end())) { 678cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); 679cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(caret, CURSOR_BACKWARD); 680cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 681cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 682cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (caret > LayoutIndexToTextIndex(run->range.start())) { 683cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); 684cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(caret, CURSOR_FORWARD); 685cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 686cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 687cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The cursor is at the edge of a run; move to the visually adjacent run. 688cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int visual_index = logical_to_visual_[run_index]; 689cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) visual_index += (direction == CURSOR_LEFT) ? -1 : 1; 690cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size())) 691cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return EdgeSelectionModel(direction); 692cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run = runs_[visual_to_logical_[visual_index]]; 693cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 694cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); 695cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return forward_motion ? FirstSelectionModelInsideRun(run) : 696cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LastSelectionModelInsideRun(run); 697cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 698cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 699cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( 700cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SelectionModel& selection, 701cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VisualCursorDirection direction) { 702cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (obscured()) 703cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return EdgeSelectionModel(direction); 704cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 705cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 706cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool success = iter.Init(); 707cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(success); 708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!success) 709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return selection; 710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 7116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Match OS specific word break behavior. 7126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(OS_WIN) 713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t pos; 714cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (direction == CURSOR_RIGHT) { 715cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pos = std::min(selection.caret_pos() + 1, text().length()); 716cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) while (iter.Advance()) { 717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pos = iter.pos(); 718cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (iter.IsWord() && pos > selection.caret_pos()) 719cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 720cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 721cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { // direction == CURSOR_LEFT 722cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Notes: We always iterate words from the beginning. 723cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This is probably fast enough for our usage, but we may 724cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // want to modify WordIterator so that it can start from the 725cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // middle of string and advance backwards. 726cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pos = std::max<int>(selection.caret_pos() - 1, 0); 727cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) while (iter.Advance()) { 728cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (iter.IsWord()) { 729cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t begin = iter.pos() - iter.GetString().length(); 730cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (begin == selection.caret_pos()) { 731cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The cursor is at the beginning of a word. 732cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Move to previous word. 733cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 734cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if (iter.pos() >= selection.caret_pos()) { 735cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The cursor is in the middle or at the end of a word. 736cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Move to the top of current word. 737cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pos = begin; 738cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 739cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 740cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pos = iter.pos() - iter.GetString().length(); 741cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 742cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 743cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 744cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(pos, CURSOR_FORWARD); 7456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#else 7466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SelectionModel cur(selection); 7476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (;;) { 7486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) cur = AdjacentCharSelectionModel(cur, direction); 7496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) size_t run = GetRunContainingCaret(cur); 7506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (run == runs_.size()) 7516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) break; 7526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const bool is_forward = runs_[run]->is_rtl == (direction == CURSOR_LEFT); 7536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) size_t cursor = cur.caret_pos(); 7546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) 7556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) break; 7566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 7576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return cur; 7586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif 759cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 760cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 761cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { 762cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!needs_layout_); 763cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(Range(0, text().length()).Contains(range)); 764cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Range layout_range(TextIndexToLayoutIndex(range.start()), 765cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) TextIndexToLayoutIndex(range.end())); 766cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range)); 767cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 768cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<Rect> rects; 769cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (layout_range.is_empty()) 770cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return rects; 771cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<Range> bounds; 772cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 773cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Add a Range for each run/selection intersection. 774cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 7755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; 776cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Range intersection = run->range.Intersect(layout_range); 7775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!intersection.IsValid()) 7785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 7795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(!intersection.is_reversed()); 7805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Range leftmost_character_x = run->GetGraphemeBounds( 7815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) grapheme_iterator_.get(), 7825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) run->is_rtl ? intersection.end() - 1 : intersection.start()); 7835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Range rightmost_character_x = run->GetGraphemeBounds( 7845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) grapheme_iterator_.get(), 7855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) run->is_rtl ? intersection.start() : intersection.end() - 1); 7865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); 7875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(!range_x.is_reversed()); 7885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (range_x.is_empty()) 7895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 7905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 7915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Union this with the last range if they're adjacent. 7925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); 7935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { 7945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) range_x = Range(bounds.back().GetMin(), range_x.GetMax()); 7955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bounds.pop_back(); 796cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 7975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bounds.push_back(range_x); 798cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 799cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < bounds.size(); ++i) { 800cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]); 801cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rects.insert(rects.end(), current_rects.begin(), current_rects.end()); 802cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 803cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return rects; 804cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 805cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 806cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)size_t RenderTextHarfBuzz::TextIndexToLayoutIndex(size_t index) const { 807cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_LE(index, text().length()); 808cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index; 809cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) CHECK_GE(i, 0); 810cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Clamp layout indices to the length of the text actually used for layout. 811cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return std::min<size_t>(GetLayoutText().length(), i); 812cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 813cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 814cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)size_t RenderTextHarfBuzz::LayoutIndexToTextIndex(size_t index) const { 815cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!obscured()) 816cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return index; 817cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 818cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_LE(index, GetLayoutText().length()); 819cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const size_t text_index = UTF16OffsetToIndex(text(), 0, index); 820cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_LE(text_index, text().length()); 821cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return text_index; 822cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 823cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 824cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool RenderTextHarfBuzz::IsValidCursorIndex(size_t index) { 825cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (index == 0 || index == text().length()) 826cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 827cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!IsValidLogicalIndex(index)) 828cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return false; 829cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) EnsureLayout(); 8305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return !grapheme_iterator_ || grapheme_iterator_->IsGraphemeBoundary(index); 831cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 832cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 833cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderTextHarfBuzz::ResetLayout() { 834cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) needs_layout_ = true; 835cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 836cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 837cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderTextHarfBuzz::EnsureLayout() { 838cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (needs_layout_) { 839cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) runs_.clear(); 8405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) grapheme_iterator_.reset(); 841cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 842cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!GetLayoutText().empty()) { 8435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) grapheme_iterator_.reset(new base::i18n::BreakIterator(GetLayoutText(), 8445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::i18n::BreakIterator::BREAK_CHARACTER)); 8455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!grapheme_iterator_->Init()) 8465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) grapheme_iterator_.reset(); 8475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 848cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ItemizeText(); 849cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 850cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) 851cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ShapeRun(runs_[i]); 852cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 853cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Precalculate run width information. 8546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) float preceding_run_widths = 0.0f; 855cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 856cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; 857cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->preceding_run_widths = preceding_run_widths; 858cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) preceding_run_widths += run->width; 859cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 860cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 861cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 862cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) needs_layout_ = false; 863cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<internal::Line> empty_lines; 864cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) set_lines(&empty_lines); 865cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 866cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 867cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (lines().empty()) { 868cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<internal::Line> lines; 869cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lines.push_back(internal::Line()); 870f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) lines[0].baseline = font_list().GetBaseline(); 871f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) lines[0].size.set_height(font_list().GetHeight()); 872cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 873cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int current_x = 0; 874cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint paint; 875cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 876cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 877cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; 878cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) internal::LineSegment segment; 879cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) segment.x_range = Range(current_x, current_x + run.width); 880cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) segment.char_range = run.range; 881cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) segment.run = i; 882cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lines[0].segments.push_back(segment); 883cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 884cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.setTypeface(run.skia_face.get()); 885cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.setTextSize(run.font_size); 886cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint::FontMetrics metrics; 887cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.getFontMetrics(&metrics); 888cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 889cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lines[0].size.set_width(lines[0].size.width() + run.width); 890cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lines[0].size.set_height(std::max(lines[0].size.height(), 8916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) metrics.fDescent - metrics.fAscent)); 892cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lines[0].baseline = std::max(lines[0].baseline, 893cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalarRoundToInt(-metrics.fAscent)); 894cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 895cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 896cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) set_lines(&lines); 897cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 898cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 899cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 900cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { 901cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!needs_layout_); 902cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) internal::SkiaTextRenderer renderer(canvas); 903cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ApplyFadeEffects(&renderer); 904cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ApplyTextShadows(&renderer); 905cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ApplyCompositionAndSelectionStyles(); 906cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 907116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int current_x = 0; 908cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Vector2d line_offset = GetLineOffset(0); 909cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 910cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; 911cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) renderer.SetTypeface(run.skia_face.get()); 912cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) renderer.SetTextSize(run.font_size); 9131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci renderer.SetFontRenderParams(run.render_params, 9141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci background_is_transparent()); 915cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 916cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline); 917116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); 918116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (size_t j = 0; j < run.glyph_count; ++j) { 919116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch positions[j] = run.positions[j]; 920116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch positions[j].offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); 921116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 922cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 923cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (BreakList<SkColor>::const_iterator it = 924cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) colors().GetBreak(run.range.start()); 925cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) it != colors().breaks().end() && it->first < run.range.end(); 926cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ++it) { 927cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Range intersection = colors().GetRange(it).Intersect(run.range); 928cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); 929cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The range may be empty if a portion of a multi-character grapheme is 930cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // selected, yielding two colors for a single glyph. For now, this just 931cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // paints the glyph with a single style, but it should paint it twice, 932cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // clipped according to selection bounds. See http://crbug.com/366786 933cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (colored_glyphs.is_empty()) 934cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) continue; 935cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 936cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) renderer.SetForegroundColor(it->second); 937116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch renderer.DrawPosText(&positions[colored_glyphs.start()], 938cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &run.glyphs[colored_glyphs.start()], 939cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) colored_glyphs.length()); 940cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int width = (colored_glyphs.end() == run.glyph_count ? run.width : 941cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run.positions[colored_glyphs.end()].x()) - 942cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run.positions[colored_glyphs.start()].x(); 943116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch renderer.DrawDecorations(origin.x(), origin.y(), width, run.underline, 944116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch run.strike, run.diagonal_strike); 945cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 946cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 947cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) current_x += run.width; 948cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 949cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 950cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) renderer.EndDiagonalStrike(); 951cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 952cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UndoCompositionAndSelectionStyles(); 953cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 954cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 955cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)size_t RenderTextHarfBuzz::GetRunContainingCaret( 956cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SelectionModel& caret) const { 957cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!needs_layout_); 958cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); 959cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LogicalCursorDirection affinity = caret.caret_affinity(); 960cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t run = 0; run < runs_.size(); ++run) { 961cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (RangeContainsCaret(runs_[run]->range, layout_position, affinity)) 962cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return run; 963cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 964cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return runs_.size(); 965cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 966cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 967cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)size_t RenderTextHarfBuzz::GetRunContainingXCoord(int x, int* offset) const { 968cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!needs_layout_); 969cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (x < 0) 970cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return runs_.size(); 971cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Find the text run containing the argument point (assumed already offset). 972cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int current_x = 0; 973cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 974cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t run = visual_to_logical_[i]; 975cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) current_x += runs_[run]->width; 976cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (x < current_x) { 977cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *offset = x - (current_x - runs_[run]->width); 978cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return run; 979cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 980cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 981cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return runs_.size(); 982cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 983cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 984cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SelectionModel RenderTextHarfBuzz::FirstSelectionModelInsideRun( 985cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const internal::TextRunHarfBuzz* run) { 986cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t position = LayoutIndexToTextIndex(run->range.start()); 987cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD); 988cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(position, CURSOR_BACKWARD); 989cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 990cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 991cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun( 992cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const internal::TextRunHarfBuzz* run) { 993cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t position = LayoutIndexToTextIndex(run->range.end()); 994cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 995cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return SelectionModel(position, CURSOR_FORWARD); 996cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 997cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 998cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderTextHarfBuzz::ItemizeText() { 999cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::string16& text = GetLayoutText(); 1000cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const bool is_text_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT; 1001cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_NE(0U, text.length()); 1002cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1003f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // If ICU fails to itemize the text, we create a run that spans the entire 1004f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // text. This is needed because leaving the runs set empty causes some clients 1005f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // to misbehave since they expect non-zero text metrics from a non-empty text. 1006cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::i18n::BiDiLineIterator bidi_iterator; 1007f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!bidi_iterator.Open(text, is_text_rtl, false)) { 1008f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; 1009f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) run->range = Range(0, text.length()); 1010f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) runs_.push_back(run); 1011f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0); 1012f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 1013f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1014cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1015cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Temporarily apply composition underlines and selection colors. 1016cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ApplyCompositionAndSelectionStyles(); 1017cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1018cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Build the list of runs from the script items and ranged styles. Use an 1019cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // empty color BreakList to avoid breaking runs at color boundaries. 1020cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BreakList<SkColor> empty_colors; 1021cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) empty_colors.SetMax(text.length()); 1022cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) internal::StyleIterator style(empty_colors, styles()); 1023cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1024cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t run_break = 0; run_break < text.length();) { 1025cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz; 1026cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->range.set_start(run_break); 1027cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | 1028cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (style.style(ITALIC) ? Font::ITALIC : 0); 1029cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->strike = style.style(STRIKE); 1030cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->diagonal_strike = style.style(DIAGONAL_STRIKE); 1031cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->underline = style.style(UNDERLINE); 1032cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1033f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int32 script_item_break = 0; 1034f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); 1035f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Odd BiDi embedding levels correspond to RTL runs. 1036f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) run->is_rtl = (run->level % 2) == 1; 1037f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Find the length and script of this script run. 1038f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) script_item_break = ScriptInterval(text, run_break, 1039f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) script_item_break - run_break, &run->script) + run_break; 1040f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1041f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Find the next break and advance the iterators as needed. 1042f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) run_break = std::min(static_cast<size_t>(script_item_break), 1043f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) TextIndexToLayoutIndex(style.GetRange().end())); 1044f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Break runs at certain characters that need to be rendered separately to 10461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // prevent either an unusual character from forcing a fallback font on the 10471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // entire run, or brackets from being affected by a fallback font. 10481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // http://crbug.com/278913, http://crbug.com/396776 1049f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (run_break > run->range.start()) 10501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci run_break = FindRunBreakingCharacter(text, run->range.start(), run_break); 1051cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1052cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(IsValidCodePointIndex(text, run_break)); 1053cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) style.UpdatePosition(LayoutIndexToTextIndex(run_break)); 1054cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->range.set_end(run_break); 1055f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1056cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) runs_.push_back(run); 1057cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1058cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1059cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Undo the temporarily applied composition underlines and selection colors. 1060cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UndoCompositionAndSelectionStyles(); 1061cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1062cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const size_t num_runs = runs_.size(); 1063cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<UBiDiLevel> levels(num_runs); 1064cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < num_runs; ++i) 1065cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) levels[i] = runs_[i]->level; 1066cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) visual_to_logical_.resize(num_runs); 1067cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]); 1068cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) logical_to_visual_.resize(num_runs); 1069cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]); 1070cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 1071cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1072cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { 1073cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Font& primary_font = font_list().GetPrimaryFont(); 10745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string primary_font_name = primary_font.GetFontName(); 1075cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->font_size = primary_font.GetFontSize(); 1076cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 10775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t best_font_missing = std::numeric_limits<size_t>::max(); 10785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string best_font; 10795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string current_font; 10805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 10815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Try shaping with |primary_font|. 10825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ShapeRunWithFont(run, primary_font_name)) { 10835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_font = primary_font_name; 10845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t current_missing = run->CountMissingGlyphs(); 10855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_missing == 0) 10865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 10875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_missing < best_font_missing) { 10885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_font_missing = current_missing; 10895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_font = current_font; 10905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 10915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 10925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 10935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_WIN) 10945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Font uniscribe_font; 10955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::char16* run_text = &(GetLayoutText()[run->range.start()]); 10965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(), 10975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &uniscribe_font) && 10985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ShapeRunWithFont(run, uniscribe_font.GetFontName())) { 10995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_font = uniscribe_font.GetFontName(); 11005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t current_missing = run->CountMissingGlyphs(); 11015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_missing == 0) 11025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 11035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_missing < best_font_missing) { 11045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_font_missing = current_missing; 11055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_font = current_font; 11065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 11075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 11085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif 11095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Try shaping with the fonts in the fallback list except the first, which is 11115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |primary_font|. 11125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<std::string> fonts = GetFallbackFontFamilies(primary_font_name); 11135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 1; i < fonts.size(); ++i) { 11145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!ShapeRunWithFont(run, fonts[i])) 11155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 11165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_font = fonts[i]; 11175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t current_missing = run->CountMissingGlyphs(); 11185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_missing == 0) 11195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 11205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_missing < best_font_missing) { 11215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_font_missing = current_missing; 11225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) best_font = current_font; 11235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 11245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 11255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!best_font.empty() && 11275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (best_font == current_font || ShapeRunWithFont(run, best_font))) { 11285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 11295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 11305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) run->glyph_count = 0; 11326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) run->width = 0.0f; 11335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 11345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, 11365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string& font_family) { 11375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::string16& text = GetLayoutText(); 11385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) skia::RefPtr<SkTypeface> skia_face = 11395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) internal::CreateSkiaTypeface(font_family, run->font_style); 11405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (skia_face == NULL) 11415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 11425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) run->skia_face = skia_face; 11431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FontRenderParamsQuery query(false); 11441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci query.families.push_back(font_family); 11451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci query.pixel_size = run->font_size; 11461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci query.style = run->font_style; 11471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci run->render_params = GetFontRenderParams(query, NULL); 1148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(), 11491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci run->font_size, run->render_params, background_is_transparent()); 1150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz 1152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // buffer holds our text, run information to be used by the shaping engine, 1153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // and the resulting glyph data. 1154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_buffer_t* buffer = hb_buffer_create(); 1155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), 1156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) text.length(), run->range.start(), run->range.length()); 1157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); 1158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_buffer_set_direction(buffer, 1159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); 1160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(ckocagil): Should we determine the actual language? 1161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_buffer_set_language(buffer, hb_language_get_default()); 1162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Shape the text. 1164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_shape(harfbuzz_font, buffer, NULL, 0); 1165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Populate the run fields with the resulting glyph data in the buffer. 1167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unsigned int glyph_count = 0; 1168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); 1169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->glyph_count = glyph_count; 11705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hb_glyph_position_t* hb_positions = 11715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hb_buffer_get_glyph_positions(buffer, NULL); 1172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->glyphs.reset(new uint16[run->glyph_count]); 11735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) run->glyph_to_char.resize(run->glyph_count); 1174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->positions.reset(new SkPoint[run->glyph_count]); 11756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) run->width = 0.0f; 1176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < run->glyph_count; ++i) { 1177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->glyphs[i] = infos[i].codepoint; 1178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) run->glyph_to_char[i] = infos[i].cluster; 11796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const int x_offset = SkFixedToScalar(hb_positions[i].x_offset); 11806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const int y_offset = SkFixedToScalar(hb_positions[i].y_offset); 1181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch run->positions[i].set(run->width + x_offset, -y_offset); 11826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) run->width += SkFixedToScalar(hb_positions[i].x_advance); 11831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(OS_LINUX) 11841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Match Pango's glyph rounding logic on Linux. 11851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!run->render_params.subpixel_positioning) 11861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci run->width = std::floor(run->width + 0.5f); 11871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif 1188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_buffer_destroy(buffer); 1191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) hb_font_destroy(harfbuzz_font); 11925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 1193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 1194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace gfx 1196