Chromium Code Reviews| 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 EnsureStringSize(); |
| 37 return Size(std::ceil(string_size_.width()), string_size_.height()); | 37 return Size(std::ceil(string_size_->width()), string_size_->height()); |
| 38 } | 38 } |
| 39 | 39 |
| 40 SizeF RenderTextMac::GetStringSizeF() { | 40 SizeF RenderTextMac::GetStringSizeF() { |
| 41 EnsureLayout(); | 41 EnsureStringSize(); |
| 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(); |
| 48 } | 48 } |
| 49 | 49 |
| 50 std::vector<RenderText::FontSpan> RenderTextMac::GetFontSpansForTesting() { | 50 std::vector<RenderText::FontSpan> RenderTextMac::GetFontSpansForTesting() { |
| 51 EnsureLayout(); | 51 EnsureLayout(); |
| 52 if (!runs_valid_) | 52 if (!runs_valid_) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 return Range(); | 87 return Range(); |
| 88 } | 88 } |
| 89 | 89 |
| 90 std::vector<Rect> RenderTextMac::GetSubstringBounds(const Range& range) { | 90 std::vector<Rect> RenderTextMac::GetSubstringBounds(const Range& range) { |
| 91 // TODO(asvitkine): Implement this. http://crbug.com/131618 | 91 // TODO(asvitkine): Implement this. http://crbug.com/131618 |
| 92 return std::vector<Rect>(); | 92 return std::vector<Rect>(); |
| 93 } | 93 } |
| 94 | 94 |
| 95 size_t RenderTextMac::TextIndexToDisplayIndex(size_t index) { | 95 size_t RenderTextMac::TextIndexToDisplayIndex(size_t index) { |
| 96 // TODO(asvitkine): Implement this. http://crbug.com/131618 | 96 // TODO(asvitkine): Implement this. http://crbug.com/131618 |
| 97 return index; | 97 return std::min(index, GetDisplayText().size()); |
|
tapted
2015/03/05 06:32:49
should this be `.size() - 1`?
Jun Mukai
2015/03/05 18:01:38
This change isn't necessary, removed.
| |
| 98 } | 98 } |
| 99 | 99 |
| 100 size_t RenderTextMac::DisplayIndexToTextIndex(size_t index) { | 100 size_t RenderTextMac::DisplayIndexToTextIndex(size_t index) { |
| 101 // TODO(asvitkine): Implement this. http://crbug.com/131618 | 101 // TODO(asvitkine): Implement this. http://crbug.com/131618 |
| 102 return index; | 102 return index; |
| 103 } | 103 } |
| 104 | 104 |
| 105 bool RenderTextMac::IsValidCursorIndex(size_t index) { | 105 bool RenderTextMac::IsValidCursorIndex(size_t index) { |
| 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 string_size_.reset(); | |
| 112 if (text_changed) { | 113 if (text_changed) { |
| 113 if (elide_behavior() != NO_ELIDE && | 114 if (elide_behavior() != NO_ELIDE && |
| 114 elide_behavior() != FADE_TAIL && | 115 elide_behavior() != FADE_TAIL && |
| 115 !layout_text().empty()) { | 116 !layout_text().empty()) { |
| 116 UpdateDisplayText(GetContentWidth()); | 117 UpdateDisplayText(GetContentWidth()); |
| 117 } else { | 118 } else { |
| 118 UpdateDisplayText(0); | 119 UpdateDisplayText(0); |
| 119 } | 120 } |
| 120 } | 121 } |
| 121 line_.reset(); | 122 line_.reset(); |
| 122 attributes_.reset(); | 123 attributes_.reset(); |
| 123 runs_.clear(); | 124 runs_.clear(); |
| 124 runs_valid_ = false; | 125 runs_valid_ = false; |
| 125 } | 126 } |
| 126 | 127 |
| 127 void RenderTextMac::OnDisplayTextAttributeChanged() { | 128 void RenderTextMac::OnDisplayTextAttributeChanged() { |
| 128 OnLayoutTextAttributeChanged(true); | 129 OnLayoutTextAttributeChanged(true); |
| 129 } | 130 } |
| 130 | 131 |
| 131 void RenderTextMac::EnsureLayout() { | 132 void RenderTextMac::EnsureLayout() { |
| 132 if (line_.get()) | 133 if (line_.get()) |
| 133 return; | 134 return; |
| 134 runs_.clear(); | 135 runs_.clear(); |
| 135 runs_valid_ = false; | 136 runs_valid_ = false; |
| 136 | 137 |
| 137 CTFontRef ct_font = base::mac::NSToCFCast( | 138 EnsureStringSize(); |
| 138 font_list().GetPrimaryFont().GetNativeFont()); | 139 EnsureLayoutInternal(GetDisplayText(), &line_, &attributes_); |
| 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 } | 140 } |
| 182 | 141 |
| 183 void RenderTextMac::DrawVisualText(Canvas* canvas) { | 142 void RenderTextMac::DrawVisualText(Canvas* canvas) { |
| 184 DCHECK(line_); | 143 DCHECK(line_); |
| 185 if (!runs_valid_) | 144 if (!runs_valid_) |
| 186 ComputeRuns(); | 145 ComputeRuns(); |
| 187 | 146 |
| 188 internal::SkiaTextRenderer renderer(canvas); | 147 internal::SkiaTextRenderer renderer(canvas); |
| 189 ApplyFadeEffects(&renderer); | 148 ApplyFadeEffects(&renderer); |
| 190 ApplyTextShadows(&renderer); | 149 ApplyTextShadows(&renderer); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 211 text_size(0), | 170 text_size(0), |
| 212 foreground(SK_ColorBLACK), | 171 foreground(SK_ColorBLACK), |
| 213 underline(false), | 172 underline(false), |
| 214 strike(false), | 173 strike(false), |
| 215 diagonal_strike(false) { | 174 diagonal_strike(false) { |
| 216 } | 175 } |
| 217 | 176 |
| 218 RenderTextMac::TextRun::~TextRun() { | 177 RenderTextMac::TextRun::~TextRun() { |
| 219 } | 178 } |
| 220 | 179 |
| 221 void RenderTextMac::ApplyStyles(CFMutableAttributedStringRef attr_string, | 180 void RenderTextMac::EnsureStringSize() { |
| 222 CTFontRef font) { | 181 if (string_size_) |
| 182 return; | |
| 183 | |
| 184 base::ScopedCFTypeRef<CTLineRef> line; | |
| 185 base::ScopedCFTypeRef<CFMutableArrayRef> attributes_owner; | |
| 186 EnsureLayoutInternal(layout_text(), &line, &attributes_owner); | |
| 187 | |
| 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 string_size_.reset(new SizeF( | |
| 203 width, std::max(ascent + descent + leading, | |
| 204 static_cast<CGFloat>(min_line_height())))); | |
| 205 common_baseline_ = ascent; | |
| 206 } | |
| 207 | |
| 208 void RenderTextMac::EnsureLayoutInternal( | |
| 209 const base::string16& text, | |
| 210 base::ScopedCFTypeRef<CTLineRef>* line, | |
| 211 base::ScopedCFTypeRef<CFMutableArrayRef>* attributes_owner) { | |
| 212 CTFontRef ct_font = base::mac::NSToCFCast( | |
| 213 font_list().GetPrimaryFont().GetNativeFont()); | |
| 214 | |
| 215 const void* keys[] = { kCTFontAttributeName }; | |
| 216 const void* values[] = { ct_font }; | |
| 217 base::ScopedCFTypeRef<CFDictionaryRef> attributes( | |
| 218 CFDictionaryCreate(NULL, | |
| 219 keys, | |
| 220 values, | |
| 221 arraysize(keys), | |
| 222 NULL, | |
| 223 &kCFTypeDictionaryValueCallBacks)); | |
| 224 | |
| 225 base::ScopedCFTypeRef<CFStringRef> cf_text( | |
| 226 base::SysUTF16ToCFStringRef(text)); | |
| 227 base::ScopedCFTypeRef<CFAttributedStringRef> attr_text( | |
| 228 CFAttributedStringCreate(NULL, cf_text, attributes)); | |
| 229 base::ScopedCFTypeRef<CFMutableAttributedStringRef> attr_text_mutable( | |
| 230 CFAttributedStringCreateMutableCopy(NULL, 0, attr_text)); | |
| 231 | |
| 232 // TODO(asvitkine|msw): Respect GetTextDirection(), which may not match the | |
| 233 // natural text direction. See kCTTypesetterOptionForcedEmbeddingLevel, etc. | |
| 234 | |
| 235 ApplyStyles(attr_text_mutable, ct_font, attributes_owner); | |
| 236 line->reset(CTLineCreateWithAttributedString(attr_text_mutable)); | |
| 237 } | |
| 238 | |
| 239 void RenderTextMac::ApplyStyles( | |
| 240 CFMutableAttributedStringRef attr_string, | |
| 241 CTFontRef font, | |
| 242 base::ScopedCFTypeRef<CFMutableArrayRef>* attributes_owner) { | |
| 223 // Temporarily apply composition underlines and selection colors. | 243 // Temporarily apply composition underlines and selection colors. |
| 224 ApplyCompositionAndSelectionStyles(); | 244 ApplyCompositionAndSelectionStyles(); |
| 225 | 245 |
| 226 // Note: CFAttributedStringSetAttribute() does not appear to retain the values | 246 // Note: CFAttributedStringSetAttribute() does not appear to retain the values |
| 227 // passed in, as can be verified via CFGetRetainCount(). To ensure the | 247 // passed in, as can be verified via CFGetRetainCount(). To ensure the |
| 228 // attribute objects do not leak, they are saved to |attributes_|. | 248 // attribute objects do not leak, they are saved to |attributes_|. |
| 229 // Clear the attributes storage. | 249 // Clear the attributes storage. |
| 230 attributes_.reset(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 250 attributes_owner->reset( |
| 251 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | |
| 231 | 252 |
| 232 // https://developer.apple.com/library/mac/#documentation/Carbon/Reference/Cor eText_StringAttributes_Ref/Reference/reference.html | 253 // https://developer.apple.com/library/mac/#documentation/Carbon/Reference/Cor eText_StringAttributes_Ref/Reference/reference.html |
| 233 internal::StyleIterator style(colors(), styles()); | 254 internal::StyleIterator style(colors(), styles()); |
| 234 const size_t layout_text_length = GetDisplayText().length(); | 255 const size_t layout_text_length = CFAttributedStringGetLength(attr_string); |
| 235 for (size_t i = 0, end = 0; i < layout_text_length; i = end) { | 256 for (size_t i = 0, end = 0; i < layout_text_length; i = end) { |
| 236 end = TextIndexToDisplayIndex(style.GetRange().end()); | 257 end = std::min(style.GetRange().end(), layout_text_length); |
| 237 const CFRange range = CFRangeMake(i, end - i); | 258 const CFRange range = CFRangeMake(i, end - i); |
| 238 base::ScopedCFTypeRef<CGColorRef> foreground( | 259 base::ScopedCFTypeRef<CGColorRef> foreground( |
| 239 CGColorCreateFromSkColor(style.color())); | 260 CGColorCreateFromSkColor(style.color())); |
| 240 CFAttributedStringSetAttribute(attr_string, range, | 261 CFAttributedStringSetAttribute(attr_string, range, |
| 241 kCTForegroundColorAttributeName, foreground); | 262 kCTForegroundColorAttributeName, foreground); |
| 242 CFArrayAppendValue(attributes_, foreground); | 263 CFArrayAppendValue(*attributes_owner, foreground); |
| 243 | 264 |
| 244 if (style.style(UNDERLINE)) { | 265 if (style.style(UNDERLINE)) { |
| 245 CTUnderlineStyle value = kCTUnderlineStyleSingle; | 266 CTUnderlineStyle value = kCTUnderlineStyleSingle; |
| 246 base::ScopedCFTypeRef<CFNumberRef> underline_value( | 267 base::ScopedCFTypeRef<CFNumberRef> underline_value( |
| 247 CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); | 268 CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); |
| 248 CFAttributedStringSetAttribute(attr_string, range, | 269 CFAttributedStringSetAttribute(attr_string, range, |
| 249 kCTUnderlineStyleAttributeName, | 270 kCTUnderlineStyleAttributeName, |
| 250 underline_value); | 271 underline_value); |
| 251 CFArrayAppendValue(attributes_, underline_value); | 272 CFArrayAppendValue(*attributes_owner, underline_value); |
| 252 } | 273 } |
| 253 | 274 |
| 254 const int traits = (style.style(BOLD) ? kCTFontBoldTrait : 0) | | 275 const int traits = (style.style(BOLD) ? kCTFontBoldTrait : 0) | |
| 255 (style.style(ITALIC) ? kCTFontItalicTrait : 0); | 276 (style.style(ITALIC) ? kCTFontItalicTrait : 0); |
| 256 if (traits != 0) { | 277 if (traits != 0) { |
| 257 base::ScopedCFTypeRef<CTFontRef> styled_font( | 278 base::ScopedCFTypeRef<CTFontRef> styled_font( |
| 258 CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, traits, traits)); | 279 CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, traits, traits)); |
| 259 // TODO(asvitkine): Handle |styled_font| == NULL case better. | 280 // TODO(asvitkine): Handle |styled_font| == NULL case better. |
| 260 if (styled_font) { | 281 if (styled_font) { |
| 261 CFAttributedStringSetAttribute(attr_string, range, kCTFontAttributeName, | 282 CFAttributedStringSetAttribute(attr_string, range, kCTFontAttributeName, |
| 262 styled_font); | 283 styled_font); |
| 263 CFArrayAppendValue(attributes_, styled_font); | 284 CFArrayAppendValue(*attributes_owner, styled_font); |
| 264 } | 285 } |
| 265 } | 286 } |
| 266 | 287 |
| 267 style.UpdatePosition(DisplayIndexToTextIndex(end)); | 288 style.UpdatePosition(DisplayIndexToTextIndex(end)); |
| 268 } | 289 } |
| 269 | 290 |
| 270 // Undo the temporarily applied composition underlines and selection colors. | 291 // Undo the temporarily applied composition underlines and selection colors. |
| 271 UndoCompositionAndSelectionStyles(); | 292 UndoCompositionAndSelectionStyles(); |
| 272 } | 293 } |
| 273 | 294 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 CTUnderlineStyle value = kCTUnderlineStyleNone; | 379 CTUnderlineStyle value = kCTUnderlineStyleNone; |
| 359 if (underline && CFNumberGetValue(underline, kCFNumberSInt32Type, &value)) | 380 if (underline && CFNumberGetValue(underline, kCFNumberSInt32Type, &value)) |
| 360 run->underline = (value == kCTUnderlineStyleSingle); | 381 run->underline = (value == kCTUnderlineStyleSingle); |
| 361 | 382 |
| 362 run_origin.offset(run_width, 0); | 383 run_origin.offset(run_width, 0); |
| 363 } | 384 } |
| 364 runs_valid_ = true; | 385 runs_valid_ = true; |
| 365 } | 386 } |
| 366 | 387 |
| 367 } // namespace gfx | 388 } // namespace gfx |
| OLD | NEW |