Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1138)

Unified Diff: ui/gfx/render_text_win.cc

Issue 17745005: Clamp RenderTextWin layout length to 10,000 code points. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Resolve string formatting; you just can't please some compilers. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« ui/base/text/text_elider.cc ('K') | « ui/gfx/render_text_unittest.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/render_text_win.cc
diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc
index 0469c0f5b7a61a6770457d330cb22d6e1c09401b..f78dfd49aa3c606aa22d6bd85cd8bfc312680f04 100644
--- a/ui/gfx/render_text_win.cc
+++ b/ui/gfx/render_text_win.cc
@@ -22,14 +22,17 @@ namespace gfx {
namespace {
-// The maximum supported number of Uniscribe runs; a SCRIPT_ITEM is 8 bytes.
-// TODO(msw): Review memory use/failure? Max string length? Alternate approach?
-const int kGuessItems = 100;
-const int kMaxItems = 10000;
+// The maximum length of text supported for Uniscribe layout and display.
+// This empirically chosen value should prevent major performance degradations.
+// TODO(msw): Support longer text, partial layout/painting, etc.
+const size_t kMaxUniscribeTextLength = 10000;
-// The maximum supported number of Uniscribe glyphs; a glyph is 1 word.
-// TODO(msw): Review memory use/failure? Max string length? Alternate approach?
-const int kMaxGlyphs = 100000;
+// The maximum supported number of text runs; an arbitrarily chosen value.
+// TODO(msw): Support more runs; see https://codereview.chromium.org/17745005
+const size_t kMaxRuns = 10000;
+
+// The maximum number of glyphs per run; ScriptShape fails on larger values.
+const size_t kMaxGlyphs = 65535;
// Callback to |EnumEnhMetaFile()| to intercept font creation.
int CALLBACK MetaFileEnumProc(HDC hdc,
@@ -181,6 +184,8 @@ RenderTextWin::RenderTextWin()
: RenderText(),
common_baseline_(0),
needs_layout_(false) {
+ set_truncate_length(kMaxUniscribeTextLength);
+
memset(&script_control_, 0, sizeof(script_control_));
memset(&script_state_, 0, sizeof(script_state_));
@@ -208,7 +213,7 @@ SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
// Find the run that contains the point and adjust the argument location.
int x = ToTextPoint(point).x();
size_t run_index = GetRunContainingXCoord(x);
- if (run_index == runs_.size())
+ if (run_index >= runs_.size())
return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
internal::TextRun* run = runs_[run_index];
@@ -345,7 +350,9 @@ void RenderTextWin::SetSelectionModel(const SelectionModel& model) {
ui::Range RenderTextWin::GetGlyphBounds(size_t index) {
const size_t run_index =
GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
- DCHECK_LT(run_index, runs_.size());
+ // Return edge bounds if the index is invalid or beyond the layout text size.
+ if (run_index >= runs_.size())
+ return ui::Range(string_size_.width());
internal::TextRun* run = runs_[run_index];
const size_t layout_index = TextIndexToLayoutIndex(index);
return ui::Range(GetGlyphXBoundary(run, layout_index, false),
@@ -386,14 +393,11 @@ std::vector<Rect> RenderTextWin::GetSubstringBounds(const ui::Range& range) {
}
size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
- if (!obscured())
- return index;
-
DCHECK_LE(index, text().length());
- const ptrdiff_t offset = ui::UTF16IndexToOffset(text(), 0, index);
- DCHECK_GE(offset, 0);
- DCHECK_LE(static_cast<size_t>(offset), GetLayoutText().length());
- return static_cast<size_t>(offset);
+ ptrdiff_t i = obscured() ? ui::UTF16IndexToOffset(text(), 0, index) : index;
+ CHECK_GE(i, 0);
+ // Clamp layout indices to the length of the text actually used for layout.
+ return std::min<size_t>(GetLayoutText().length(), i);
}
size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const {
@@ -496,23 +500,23 @@ void RenderTextWin::ItemizeLogicalText() {
HRESULT hr = E_OUTOFMEMORY;
int script_items_count = 0;
std::vector<SCRIPT_ITEM> script_items;
- const size_t text_length = GetLayoutText().length();
- for (size_t n = kGuessItems; hr == E_OUTOFMEMORY && n < kMaxItems; n *= 2) {
+
+ // Guess the run count based on string sizes; Uniscribe requires 3 at minimum.
+ const size_t layout_text_length = GetLayoutText().length();
+ size_t run_guess = std::min(kMaxRuns, std::max(3U, layout_text_length / 10));
Alexei Svitkine (slow) 2013/06/28 15:37:02 The old code would start at 100 whereas your new c
msw 2013/06/28 16:31:23 Done.
+ while (hr == E_OUTOFMEMORY && run_guess <= kMaxRuns) {
// Derive the array of Uniscribe script items from the logical text.
- // ScriptItemize always adds a terminal array item so that the length of the
- // last item can be derived from the terminal SCRIPT_ITEM::iCharPos.
- script_items.resize(n);
- hr = ScriptItemize(GetLayoutText().c_str(),
- text_length,
- n - 1,
- &script_control_,
- &script_state_,
- &script_items[0],
- &script_items_count);
+ // ScriptItemize always adds a terminal array item so that the length of
+ // the last item can be derived from the terminal SCRIPT_ITEM::iCharPos.
+ script_items.resize(run_guess);
+ hr = ScriptItemize(GetLayoutText().c_str(), layout_text_length,
+ run_guess - 1, &script_control_, &script_state_,
+ &script_items[0], &script_items_count);
+ // Ensure that |kMaxRuns| is attempted and the loop terminates afterward.
+ run_guess = std::max(run_guess + 1, std::min(run_guess * 2, kMaxRuns));
}
DCHECK(SUCCEEDED(hr));
-
- if (script_items_count <= 0)
+ if (!SUCCEEDED(hr) || script_items_count <= 0)
return;
// Temporarily apply composition underlines and selection colors.
@@ -522,7 +526,7 @@ void RenderTextWin::ItemizeLogicalText() {
// TODO(msw): Only break for bold/italic, not color etc. See TextRun comment.
internal::StyleIterator style(colors(), styles());
SCRIPT_ITEM* script_item = &script_items[0];
- const size_t layout_text_length = GetLayoutText().length();
+ const size_t max_run_length = kMaxGlyphs / 2;
for (size_t run_break = 0; run_break < layout_text_length;) {
internal::TextRun* run = new internal::TextRun();
run->range.set_start(run_break);
@@ -541,6 +545,9 @@ void RenderTextWin::ItemizeLogicalText() {
const size_t script_item_break = (script_item + 1)->iCharPos;
run_break = std::min(script_item_break,
TextIndexToLayoutIndex(style.GetRange().end()));
+ // Clamp run lengths to avoid exceeding the maximum supported glyph count.
+ if ((run_break - run->range.start()) > max_run_length)
+ run_break = run->range.start() + max_run_length;
style.UpdatePosition(LayoutIndexToTextIndex(run_break));
if (script_item_break == run_break)
script_item++;
@@ -740,23 +747,19 @@ HRESULT RenderTextWin::ShapeTextRunWithFont(internal::TextRun* run,
HRESULT hr = E_OUTOFMEMORY;
const size_t run_length = run->range.length();
const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
- // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx
+ // Guess the expected number of glyphs from the length of the run.
+ // MSDN suggests this at http://msdn.microsoft.com/en-us/library/dd368564.aspx
size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16);
- while (hr == E_OUTOFMEMORY && max_glyphs < kMaxGlyphs) {
+ while (hr == E_OUTOFMEMORY && max_glyphs <= kMaxGlyphs) {
run->glyph_count = 0;
run->glyphs.reset(new WORD[max_glyphs]);
run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
- hr = ScriptShape(cached_hdc_,
- &run->script_cache,
- run_text,
- run_length,
- max_glyphs,
- &run->script_analysis,
- run->glyphs.get(),
- run->logical_clusters.get(),
- run->visible_attributes.get(),
+ hr = ScriptShape(cached_hdc_, &run->script_cache, run_text, run_length,
+ max_glyphs, &run->script_analysis, run->glyphs.get(),
+ run->logical_clusters.get(), run->visible_attributes.get(),
&run->glyph_count);
- max_glyphs *= 2;
+ // Ensure that |kMaxGlyphs| is attempted and the loop terminates afterward.
+ max_glyphs = std::max(max_glyphs + 1, std::min(max_glyphs * 2, kMaxGlyphs));
Alexei Svitkine (slow) 2013/06/28 15:37:02 How about making a helper function for this constr
msw 2013/06/28 16:31:23 I'll pass; 3 uses or real complexity constitutes a
}
return hr;
}
« ui/base/text/text_elider.cc ('K') | « ui/gfx/render_text_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698