15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/render_text_mac.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ApplicationServices/ApplicationServices.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <algorithm> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/foundation_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/skia_utils_mac.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RenderTextMac::RenderTextMac() : common_baseline_(0), runs_valid_(false) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RenderTextMac::~RenderTextMac() { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Size RenderTextMac::GetStringSize() { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return Size(std::ceil(string_size_.width()), string_size_.height()); 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)SizeF RenderTextMac::GetStringSizeF() { 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) EnsureLayout(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return string_size_; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectionModel RenderTextMac::FindCursorPosition(const Point& point) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<RenderText::FontSpan> RenderTextMac::GetFontSpansForTesting() { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureLayout(); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!runs_valid_) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ComputeRuns(); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<RenderText::FontSpan> spans; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) Font font(runs_[i].font_name, runs_[i].text_size); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CFRange cf_range = CTRunGetStringRange(runs_[i].ct_run); 50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const Range range(cf_range.location, cf_range.location + cf_range.length); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) spans.push_back(RenderText::FontSpan(font, range)); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return spans; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)int RenderTextMac::GetLayoutTextBaseline() { 580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) EnsureLayout(); 590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return common_baseline_; 600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectionModel RenderTextMac::AdjacentCharSelectionModel( 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SelectionModel& selection, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VisualCursorDirection direction) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SelectionModel RenderTextMac::AdjacentWordSelectionModel( 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SelectionModel& selection, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VisualCursorDirection direction) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SelectionModel(); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Range RenderTextMac::GetGlyphBounds(size_t index) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 78d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return Range(); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 81d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)std::vector<Rect> RenderTextMac::GetSubstringBounds(const Range& range) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::vector<Rect>(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t RenderTextMac::TextIndexToLayoutIndex(size_t index) const { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t RenderTextMac::LayoutIndexToTextIndex(size_t index) const { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool RenderTextMac::IsValidCursorIndex(size_t index) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Implement this. http://crbug.com/131618 98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return IsValidLogicalIndex(index); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RenderTextMac::ResetLayout() { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_.reset(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attributes_.reset(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) runs_.clear(); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) runs_valid_ = false; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RenderTextMac::EnsureLayout() { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line_.get()) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) runs_.clear(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) runs_valid_ = false; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CTFontRef ct_font = base::mac::NSToCFCast( 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) font_list().GetPrimaryFont().GetNativeFont()); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* keys[] = { kCTFontAttributeName }; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* values[] = { ct_font }; 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFDictionaryRef> attributes( 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CFDictionaryCreate(NULL, 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch keys, 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch values, 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch arraysize(keys), 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NULL, 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &kCFTypeDictionaryValueCallBacks)); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFStringRef> cf_text( 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SysUTF16ToCFStringRef(text())); 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFAttributedStringRef> attr_text( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFAttributedStringCreate(NULL, cf_text, attributes)); 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFMutableAttributedStringRef> attr_text_mutable( 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFAttributedStringCreateMutableCopy(NULL, 0, attr_text)); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine|msw): Respect GetTextDirection(), which may not match the 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // natural text direction. See kCTTypesetterOptionForcedEmbeddingLevel, etc. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyStyles(attr_text_mutable, ct_font); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_.reset(CTLineCreateWithAttributedString(attr_text_mutable)); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGFloat ascent = 0; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGFloat descent = 0; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGFloat leading = 0; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Consider using CTLineGetBoundsWithOptions() on 10.8+. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double width = CTLineGetTypographicBounds(line_, &ascent, &descent, &leading); 145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Ensure ascent and descent are not smaller than ones of the font list. 146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Keep them tall enough to draw often-used characters. 147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // For example, if a text field contains a Japanese character, which is 148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // smaller than Latin ones, and then later a Latin one is inserted, this 149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // ensures that the text baseline does not shift. 150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) CGFloat font_list_height = font_list().GetHeight(); 151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) CGFloat font_list_baseline = font_list().GetBaseline(); 152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ascent = std::max(ascent, font_list_baseline); 153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) descent = std::max(descent, font_list_height - font_list_baseline); 1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) string_size_ = SizeF(width, ascent + descent + leading); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) common_baseline_ = ascent; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RenderTextMac::DrawVisualText(Canvas* canvas) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(line_); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!runs_valid_) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ComputeRuns(); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal::SkiaTextRenderer renderer(canvas); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyFadeEffects(&renderer); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyTextShadows(&renderer); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < runs_.size(); ++i) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TextRun& run = runs_[i]; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.SetForegroundColor(run.foreground); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.SetTextSize(run.text_size); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.SetFontFamilyWithStyle(run.font_name, run.font_style); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.DrawPosText(&run.glyph_positions[0], &run.glyphs[0], 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run.glyphs.size()); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) renderer.DrawDecorations(run.origin.x(), run.origin.y(), run.width, 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) run.underline, run.strike, run.diagonal_strike); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch renderer.EndDiagonalStrike(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RenderTextMac::TextRun::TextRun() 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : ct_run(NULL), 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) origin(SkPoint::Make(0, 0)), 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width(0), 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) font_style(Font::NORMAL), 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_size(0), 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) foreground(SK_ColorBLACK), 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) underline(false), 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) strike(false), 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagonal_strike(false) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RenderTextMac::TextRun::~TextRun() { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RenderTextMac::ApplyStyles(CFMutableAttributedStringRef attr_string, 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTFontRef font) { 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Temporarily apply composition underlines and selection colors. 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ApplyCompositionAndSelectionStyles(); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note: CFAttributedStringSetAttribute() does not appear to retain the values 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // passed in, as can be verified via CFGetRetainCount(). To ensure the 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // attribute objects do not leak, they are saved to |attributes_|. 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Clear the attributes storage. 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) attributes_.reset(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // https://developer.apple.com/library/mac/#documentation/Carbon/Reference/CoreText_StringAttributes_Ref/Reference/reference.html 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) internal::StyleIterator style(colors(), styles()); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const size_t layout_text_length = GetLayoutText().length(); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0, end = 0; i < layout_text_length; i = end) { 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) end = TextIndexToLayoutIndex(style.GetRange().end()); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CFRange range = CFRangeMake(i, end - i); 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CGColorRef> foreground( 214010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) CGColorCreateFromSkColor(style.color())); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFAttributedStringSetAttribute(attr_string, range, 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kCTForegroundColorAttributeName, foreground); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayAppendValue(attributes_, foreground); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (style.style(UNDERLINE)) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTUnderlineStyle value = kCTUnderlineStyleSingle; 221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFNumberRef> underline_value( 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFAttributedStringSetAttribute(attr_string, range, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCTUnderlineStyleAttributeName, 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) underline_value); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CFArrayAppendValue(attributes_, underline_value); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int traits = (style.style(BOLD) ? kCTFontBoldTrait : 0) | 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (style.style(ITALIC) ? kCTFontItalicTrait : 0); 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (traits != 0) { 232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CTFontRef> styled_font( 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, traits, traits)); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Handle |styled_font| == NULL case better. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (styled_font) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFAttributedStringSetAttribute(attr_string, range, kCTFontAttributeName, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styled_font); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayAppendValue(attributes_, styled_font); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) style.UpdatePosition(LayoutIndexToTextIndex(end)); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Undo the temporarily applied composition underlines and selection colors. 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UndoCompositionAndSelectionStyles(); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RenderTextMac::ComputeRuns() { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(line_); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayRef ct_runs = CTLineGetGlyphRuns(line_); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CFIndex ct_runs_count = CFArrayGetCount(ct_runs); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // TODO(asvitkine): Don't use GetLineOffset() until draw time, since it may be 25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // updated based on alignment changes without resetting the layout. 257010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) Vector2d text_offset = GetLineOffset(0); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skia will draw glyphs with respect to the baseline. 259010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) text_offset += Vector2d(0, common_baseline_); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkScalar x = SkIntToScalar(text_offset.x()); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkScalar y = SkIntToScalar(text_offset.y()); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPoint run_origin = SkPoint::Make(x, y); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CFRange empty_cf_range = CFRangeMake(0, 0); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CFIndex i = 0; i < ct_runs_count; ++i) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTRunRef ct_run = 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::CFCast<CTRunRef>(CFArrayGetValueAtIndex(ct_runs, i)); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t glyph_count = CTRunGetGlyphCount(ct_run); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double run_width = 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTRunGetTypographicBounds(ct_run, empty_cf_range, NULL, NULL, NULL); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (glyph_count == 0) { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_origin.offset(run_width, 0); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) runs_.push_back(TextRun()); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextRun* run = &runs_.back(); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->ct_run = ct_run; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->origin = run_origin; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->width = run_width; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->glyphs.resize(glyph_count); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTRunGetGlyphs(ct_run, empty_cf_range, &run->glyphs[0]); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CTRunGetGlyphs() sometimes returns glyphs with value 65535 and zero 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // width (this has been observed at the beginning of a string containing 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Arabic content). Passing these to Skia will trigger an assertion; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // instead set their values to 0. 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t glyph = 0; glyph < glyph_count; glyph++) { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (run->glyphs[glyph] == 65535) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->glyphs[glyph] = 0; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->glyph_positions.resize(glyph_count); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CGPoint* positions_ptr = CTRunGetPositionsPtr(ct_run); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<CGPoint> positions; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (positions_ptr == NULL) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) positions.resize(glyph_count); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTRunGetPositions(ct_run, empty_cf_range, &positions[0]); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) positions_ptr = &positions[0]; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t glyph = 0; glyph < glyph_count; glyph++) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPoint* point = &run->glyph_positions[glyph]; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) point->set(x + SkDoubleToScalar(positions_ptr[glyph].x), 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y + SkDoubleToScalar(positions_ptr[glyph].y)); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asvitkine): Style boundaries are not necessarily per-run. Handle 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // this better. Also, support strike and diagonal_strike. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFDictionaryRef attributes = CTRunGetAttributes(ct_run); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTFontRef ct_font = 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::GetValueFromDictionary<CTFontRef>(attributes, 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCTFontAttributeName); 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFStringRef> font_name_ref( 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTFontCopyFamilyName(ct_font)); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->font_name = base::SysCFStringRefToUTF8(font_name_ref); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->text_size = CTFontGetSize(ct_font); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ct_font); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (traits & kCTFontBoldTrait) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->font_style |= Font::BOLD; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (traits & kCTFontItalicTrait) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run->font_style |= Font::ITALIC; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CGColorRef foreground = 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::GetValueFromDictionary<CGColorRef>( 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attributes, kCTForegroundColorAttributeName); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (foreground) 328010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) run->foreground = CGColorRefToSkColor(foreground); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CFNumberRef underline = 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::GetValueFromDictionary<CFNumberRef>( 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attributes, kCTUnderlineStyleAttributeName); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CTUnderlineStyle value = kCTUnderlineStyleNone; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (underline && CFNumberGetValue(underline, kCFNumberSInt32Type, &value)) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) run->underline = (value == kCTUnderlineStyleSingle); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_origin.offset(run_width, 0); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) runs_valid_ = true; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)RenderText* RenderText::CreateNativeInstance() { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new RenderTextMac; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace gfx 347