OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/render_text_mac.h" | 5 #include "ui/gfx/render_text_mac.h" |
6 | 6 |
7 #include <ApplicationServices/ApplicationServices.h> | 7 #include <ApplicationServices/ApplicationServices.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 15 matching lines...) Expand all Loading... | |
26 | 26 |
27 scoped_ptr<RenderText> RenderTextMac::CreateInstanceOfSameType() const { | 27 scoped_ptr<RenderText> RenderTextMac::CreateInstanceOfSameType() const { |
28 return make_scoped_ptr(new RenderTextMac); | 28 return make_scoped_ptr(new RenderTextMac); |
29 } | 29 } |
30 | 30 |
31 const base::string16& RenderTextMac::GetDisplayText() { | 31 const base::string16& RenderTextMac::GetDisplayText() { |
32 return text_elided() ? display_text() : layout_text(); | 32 return text_elided() ? display_text() : layout_text(); |
33 } | 33 } |
34 | 34 |
35 Size RenderTextMac::GetStringSize() { | 35 Size RenderTextMac::GetStringSize() { |
36 EnsureLayout(); | 36 gfx::SizeF size_f = GetStringSizeF(); |
37 return Size(std::ceil(string_size_.width()), string_size_.height()); | 37 return Size(std::ceil(size_f.width()), size_f.height()); |
oshima
2015/03/05 21:27:58
nit: gfx::ToCeiledSize ?
Jun Mukai
2015/03/06 01:32:38
Done.
| |
38 } | 38 } |
39 | 39 |
40 SizeF RenderTextMac::GetStringSizeF() { | 40 SizeF RenderTextMac::GetStringSizeF() { |
41 EnsureLayout(); | 41 EnsureLayout(); |
42 return string_size_; | 42 return string_size_; |
43 } | 43 } |
44 | 44 |
45 SelectionModel RenderTextMac::FindCursorPosition(const Point& point) { | 45 SelectionModel RenderTextMac::FindCursorPosition(const Point& point) { |
46 // TODO(asvitkine): Implement this. http://crbug.com/131618 | 46 // TODO(asvitkine): Implement this. http://crbug.com/131618 |
47 return SelectionModel(); | 47 return SelectionModel(); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
106 // TODO(asvitkine): Implement this. http://crbug.com/131618 | 106 // TODO(asvitkine): Implement this. http://crbug.com/131618 |
107 return IsValidLogicalIndex(index); | 107 return IsValidLogicalIndex(index); |
108 } | 108 } |
109 | 109 |
110 void RenderTextMac::OnLayoutTextAttributeChanged(bool text_changed) { | 110 void RenderTextMac::OnLayoutTextAttributeChanged(bool text_changed) { |
111 DCHECK(!multiline()) << "RenderTextMac does not support multi line"; | 111 DCHECK(!multiline()) << "RenderTextMac does not support multi line"; |
112 if (text_changed) { | 112 if (text_changed) { |
113 if (elide_behavior() != NO_ELIDE && | 113 if (elide_behavior() != NO_ELIDE && |
114 elide_behavior() != FADE_TAIL && | 114 elide_behavior() != FADE_TAIL && |
115 !layout_text().empty()) { | 115 !layout_text().empty()) { |
116 UpdateDisplayText(GetContentWidth()); | 116 UpdateDisplayText(std::ceil(GetLayoutTextSize().width())); |
oshima
2015/03/05 21:27:58
It's probably better to rename it to GetLayoutText
msw
2015/03/05 21:55:29
The postfix 'F' implies that it returns a floating
oshima
2015/03/05 23:09:11
Oops, yes. Just GetLayoutTextWidth.
Jun Mukai
2015/03/06 01:32:38
Done.
| |
117 } else { | 117 } else { |
118 UpdateDisplayText(0); | 118 UpdateDisplayText(0); |
119 } | 119 } |
120 } | 120 } |
121 line_.reset(); | 121 line_.reset(); |
122 attributes_.reset(); | 122 attributes_.reset(); |
123 runs_.clear(); | 123 runs_.clear(); |
124 runs_valid_ = false; | 124 runs_valid_ = false; |
125 } | 125 } |
126 | 126 |
127 void RenderTextMac::OnDisplayTextAttributeChanged() { | 127 void RenderTextMac::OnDisplayTextAttributeChanged() { |
128 OnLayoutTextAttributeChanged(true); | 128 OnLayoutTextAttributeChanged(true); |
129 } | 129 } |
130 | 130 |
131 void RenderTextMac::EnsureLayout() { | 131 void RenderTextMac::EnsureLayout() { |
132 if (line_.get()) | 132 if (line_.get()) |
133 return; | 133 return; |
134 runs_.clear(); | 134 runs_.clear(); |
135 runs_valid_ = false; | 135 runs_valid_ = false; |
136 | 136 |
137 CTFontRef ct_font = base::mac::NSToCFCast( | 137 line_ = EnsureLayoutInternal(GetDisplayText(), &attributes_); |
138 font_list().GetPrimaryFont().GetNativeFont()); | 138 string_size_ = GetCTLineSize(line_.get(), &common_baseline_); |
139 | |
140 const void* keys[] = { kCTFontAttributeName }; | |
141 const void* values[] = { ct_font }; | |
142 base::ScopedCFTypeRef<CFDictionaryRef> attributes( | |
143 CFDictionaryCreate(NULL, | |
144 keys, | |
145 values, | |
146 arraysize(keys), | |
147 NULL, | |
148 &kCFTypeDictionaryValueCallBacks)); | |
149 | |
150 base::ScopedCFTypeRef<CFStringRef> cf_text( | |
151 base::SysUTF16ToCFStringRef(text())); | |
152 base::ScopedCFTypeRef<CFAttributedStringRef> attr_text( | |
153 CFAttributedStringCreate(NULL, cf_text, attributes)); | |
154 base::ScopedCFTypeRef<CFMutableAttributedStringRef> attr_text_mutable( | |
155 CFAttributedStringCreateMutableCopy(NULL, 0, attr_text)); | |
156 | |
157 // TODO(asvitkine|msw): Respect GetTextDirection(), which may not match the | |
158 // natural text direction. See kCTTypesetterOptionForcedEmbeddingLevel, etc. | |
159 | |
160 ApplyStyles(attr_text_mutable, ct_font); | |
161 line_.reset(CTLineCreateWithAttributedString(attr_text_mutable)); | |
162 | |
163 CGFloat ascent = 0; | |
164 CGFloat descent = 0; | |
165 CGFloat leading = 0; | |
166 // TODO(asvitkine): Consider using CTLineGetBoundsWithOptions() on 10.8+. | |
167 double width = CTLineGetTypographicBounds(line_, &ascent, &descent, &leading); | |
168 // Ensure ascent and descent are not smaller than ones of the font list. | |
169 // Keep them tall enough to draw often-used characters. | |
170 // For example, if a text field contains a Japanese character, which is | |
171 // smaller than Latin ones, and then later a Latin one is inserted, this | |
172 // ensures that the text baseline does not shift. | |
173 CGFloat font_list_height = font_list().GetHeight(); | |
174 CGFloat font_list_baseline = font_list().GetBaseline(); | |
175 ascent = std::max(ascent, font_list_baseline); | |
176 descent = std::max(descent, font_list_height - font_list_baseline); | |
177 string_size_ = | |
178 SizeF(width, std::max(ascent + descent + leading, | |
179 static_cast<CGFloat>(min_line_height()))); | |
180 common_baseline_ = ascent; | |
181 } | 139 } |
182 | 140 |
183 void RenderTextMac::DrawVisualText(Canvas* canvas) { | 141 void RenderTextMac::DrawVisualText(Canvas* canvas) { |
184 DCHECK(line_); | 142 DCHECK(line_); |
185 if (!runs_valid_) | 143 if (!runs_valid_) |
186 ComputeRuns(); | 144 ComputeRuns(); |
187 | 145 |
188 internal::SkiaTextRenderer renderer(canvas); | 146 internal::SkiaTextRenderer renderer(canvas); |
189 ApplyFadeEffects(&renderer); | 147 ApplyFadeEffects(&renderer); |
190 ApplyTextShadows(&renderer); | 148 ApplyTextShadows(&renderer); |
(...skipping 20 matching lines...) Expand all Loading... | |
211 text_size(0), | 169 text_size(0), |
212 foreground(SK_ColorBLACK), | 170 foreground(SK_ColorBLACK), |
213 underline(false), | 171 underline(false), |
214 strike(false), | 172 strike(false), |
215 diagonal_strike(false) { | 173 diagonal_strike(false) { |
216 } | 174 } |
217 | 175 |
218 RenderTextMac::TextRun::~TextRun() { | 176 RenderTextMac::TextRun::~TextRun() { |
219 } | 177 } |
220 | 178 |
221 void RenderTextMac::ApplyStyles(CFMutableAttributedStringRef attr_string, | 179 gfx::SizeF RenderTextMac::GetLayoutTextSize() { |
222 CTFontRef font) { | 180 base::ScopedCFTypeRef<CFMutableArrayRef> attributes_owner; |
181 base::ScopedCFTypeRef<CTLineRef> line( | |
182 EnsureLayoutInternal(layout_text(), &attributes_owner)); | |
183 SkScalar baseline; | |
184 return GetCTLineSize(line.get(), &baseline); | |
185 } | |
186 | |
187 gfx::SizeF RenderTextMac::GetCTLineSize(CTLineRef line, SkScalar* baseline) { | |
188 CGFloat ascent = 0; | |
189 CGFloat descent = 0; | |
190 CGFloat leading = 0; | |
191 // TODO(asvitkine): Consider using CTLineGetBoundsWithOptions() on 10.8+. | |
192 double width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading); | |
193 // Ensure ascent and descent are not smaller than ones of the font list. | |
194 // Keep them tall enough to draw often-used characters. | |
195 // For example, if a text field contains a Japanese character, which is | |
196 // smaller than Latin ones, and then later a Latin one is inserted, this | |
197 // ensures that the text baseline does not shift. | |
198 CGFloat font_list_height = font_list().GetHeight(); | |
199 CGFloat font_list_baseline = font_list().GetBaseline(); | |
200 ascent = std::max(ascent, font_list_baseline); | |
201 descent = std::max(descent, font_list_height - font_list_baseline); | |
202 *baseline = ascent; | |
203 return SizeF( | |
204 width, std::max(ascent + descent + leading, | |
205 static_cast<CGFloat>(min_line_height()))); | |
206 } | |
207 | |
208 base::ScopedCFTypeRef<CTLineRef> RenderTextMac::EnsureLayoutInternal( | |
209 const base::string16& text, | |
210 base::ScopedCFTypeRef<CFMutableArrayRef>* attributes_owner) { | |
211 CTFontRef ct_font = base::mac::NSToCFCast( | |
212 font_list().GetPrimaryFont().GetNativeFont()); | |
213 | |
214 const void* keys[] = { kCTFontAttributeName }; | |
215 const void* values[] = { ct_font }; | |
216 base::ScopedCFTypeRef<CFDictionaryRef> attributes( | |
217 CFDictionaryCreate(NULL, | |
218 keys, | |
219 values, | |
220 arraysize(keys), | |
221 NULL, | |
222 &kCFTypeDictionaryValueCallBacks)); | |
223 | |
224 base::ScopedCFTypeRef<CFStringRef> cf_text( | |
225 base::SysUTF16ToCFStringRef(text)); | |
226 base::ScopedCFTypeRef<CFAttributedStringRef> attr_text( | |
227 CFAttributedStringCreate(NULL, cf_text, attributes)); | |
228 base::ScopedCFTypeRef<CFMutableAttributedStringRef> attr_text_mutable( | |
229 CFAttributedStringCreateMutableCopy(NULL, 0, attr_text)); | |
230 | |
231 // TODO(asvitkine|msw): Respect GetTextDirection(), which may not match the | |
232 // natural text direction. See kCTTypesetterOptionForcedEmbeddingLevel, etc. | |
233 | |
234 *attributes_owner = ApplyStyles(attr_text_mutable, ct_font); | |
235 return base::ScopedCFTypeRef<CTLineRef>( | |
236 CTLineCreateWithAttributedString(attr_text_mutable)); | |
237 } | |
238 | |
239 base::ScopedCFTypeRef<CFMutableArrayRef> RenderTextMac::ApplyStyles( | |
240 CFMutableAttributedStringRef attr_string, | |
241 CTFontRef font) { | |
223 // Temporarily apply composition underlines and selection colors. | 242 // Temporarily apply composition underlines and selection colors. |
224 ApplyCompositionAndSelectionStyles(); | 243 ApplyCompositionAndSelectionStyles(); |
225 | 244 |
226 // Note: CFAttributedStringSetAttribute() does not appear to retain the values | 245 // Note: CFAttributedStringSetAttribute() does not appear to retain the values |
227 // passed in, as can be verified via CFGetRetainCount(). To ensure the | 246 // passed in, as can be verified via CFGetRetainCount(). To ensure the |
228 // attribute objects do not leak, they are saved to |attributes_|. | 247 // attribute objects do not leak, they are saved to |attributes_|. |
229 // Clear the attributes storage. | 248 // Clear the attributes storage. |
230 attributes_.reset(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 249 base::ScopedCFTypeRef<CFMutableArrayRef> attributes( |
250 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | |
231 | 251 |
232 // https://developer.apple.com/library/mac/#documentation/Carbon/Reference/Cor eText_StringAttributes_Ref/Reference/reference.html | 252 // https://developer.apple.com/library/mac/#documentation/Carbon/Reference/Cor eText_StringAttributes_Ref/Reference/reference.html |
233 internal::StyleIterator style(colors(), styles()); | 253 internal::StyleIterator style(colors(), styles()); |
234 const size_t layout_text_length = GetDisplayText().length(); | 254 const size_t layout_text_length = CFAttributedStringGetLength(attr_string); |
235 for (size_t i = 0, end = 0; i < layout_text_length; i = end) { | 255 for (size_t i = 0, end = 0; i < layout_text_length; i = end) { |
236 end = TextIndexToDisplayIndex(style.GetRange().end()); | 256 end = std::min(style.GetRange().end(), layout_text_length); |
msw
2015/03/05 21:55:29
nit q: should this use something like TextIndexToG
Jun Mukai
2015/03/06 01:32:38
good idea. done.
| |
237 const CFRange range = CFRangeMake(i, end - i); | 257 const CFRange range = CFRangeMake(i, end - i); |
238 base::ScopedCFTypeRef<CGColorRef> foreground( | 258 base::ScopedCFTypeRef<CGColorRef> foreground( |
239 CGColorCreateFromSkColor(style.color())); | 259 CGColorCreateFromSkColor(style.color())); |
240 CFAttributedStringSetAttribute(attr_string, range, | 260 CFAttributedStringSetAttribute(attr_string, range, |
241 kCTForegroundColorAttributeName, foreground); | 261 kCTForegroundColorAttributeName, foreground); |
242 CFArrayAppendValue(attributes_, foreground); | 262 CFArrayAppendValue(attributes, foreground); |
243 | 263 |
244 if (style.style(UNDERLINE)) { | 264 if (style.style(UNDERLINE)) { |
245 CTUnderlineStyle value = kCTUnderlineStyleSingle; | 265 CTUnderlineStyle value = kCTUnderlineStyleSingle; |
246 base::ScopedCFTypeRef<CFNumberRef> underline_value( | 266 base::ScopedCFTypeRef<CFNumberRef> underline_value( |
247 CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); | 267 CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); |
248 CFAttributedStringSetAttribute(attr_string, range, | 268 CFAttributedStringSetAttribute(attr_string, range, |
249 kCTUnderlineStyleAttributeName, | 269 kCTUnderlineStyleAttributeName, |
250 underline_value); | 270 underline_value); |
251 CFArrayAppendValue(attributes_, underline_value); | 271 CFArrayAppendValue(attributes, underline_value); |
252 } | 272 } |
253 | 273 |
254 const int traits = (style.style(BOLD) ? kCTFontBoldTrait : 0) | | 274 const int traits = (style.style(BOLD) ? kCTFontBoldTrait : 0) | |
255 (style.style(ITALIC) ? kCTFontItalicTrait : 0); | 275 (style.style(ITALIC) ? kCTFontItalicTrait : 0); |
256 if (traits != 0) { | 276 if (traits != 0) { |
257 base::ScopedCFTypeRef<CTFontRef> styled_font( | 277 base::ScopedCFTypeRef<CTFontRef> styled_font( |
258 CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, traits, traits)); | 278 CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, traits, traits)); |
259 // TODO(asvitkine): Handle |styled_font| == NULL case better. | 279 // TODO(asvitkine): Handle |styled_font| == NULL case better. |
260 if (styled_font) { | 280 if (styled_font) { |
261 CFAttributedStringSetAttribute(attr_string, range, kCTFontAttributeName, | 281 CFAttributedStringSetAttribute(attr_string, range, kCTFontAttributeName, |
262 styled_font); | 282 styled_font); |
263 CFArrayAppendValue(attributes_, styled_font); | 283 CFArrayAppendValue(attributes, styled_font); |
264 } | 284 } |
265 } | 285 } |
266 | 286 |
267 style.UpdatePosition(DisplayIndexToTextIndex(end)); | 287 style.UpdatePosition(DisplayIndexToTextIndex(end)); |
268 } | 288 } |
269 | 289 |
270 // Undo the temporarily applied composition underlines and selection colors. | 290 // Undo the temporarily applied composition underlines and selection colors. |
271 UndoCompositionAndSelectionStyles(); | 291 UndoCompositionAndSelectionStyles(); |
292 | |
293 return attributes; | |
272 } | 294 } |
273 | 295 |
274 void RenderTextMac::ComputeRuns() { | 296 void RenderTextMac::ComputeRuns() { |
275 DCHECK(line_); | 297 DCHECK(line_); |
276 | 298 |
277 CFArrayRef ct_runs = CTLineGetGlyphRuns(line_); | 299 CFArrayRef ct_runs = CTLineGetGlyphRuns(line_); |
278 const CFIndex ct_runs_count = CFArrayGetCount(ct_runs); | 300 const CFIndex ct_runs_count = CFArrayGetCount(ct_runs); |
279 | 301 |
280 // TODO(asvitkine): Don't use GetLineOffset() until draw time, since it may be | 302 // TODO(asvitkine): Don't use GetLineOffset() until draw time, since it may be |
281 // updated based on alignment changes without resetting the layout. | 303 // updated based on alignment changes without resetting the layout. |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
358 CTUnderlineStyle value = kCTUnderlineStyleNone; | 380 CTUnderlineStyle value = kCTUnderlineStyleNone; |
359 if (underline && CFNumberGetValue(underline, kCFNumberSInt32Type, &value)) | 381 if (underline && CFNumberGetValue(underline, kCFNumberSInt32Type, &value)) |
360 run->underline = (value == kCTUnderlineStyleSingle); | 382 run->underline = (value == kCTUnderlineStyleSingle); |
361 | 383 |
362 run_origin.offset(run_width, 0); | 384 run_origin.offset(run_width, 0); |
363 } | 385 } |
364 runs_valid_ = true; | 386 runs_valid_ = true; |
365 } | 387 } |
366 | 388 |
367 } // namespace gfx | 389 } // namespace gfx |
OLD | NEW |