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

Side by Side Diff: chrome/browser/chromeos/input_method/candidate_window.cc

Issue 5444001: Speed up rendering of the input method candidate window. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 10 years 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/chromeos/input_method/candidate_window.h" 5 #include "chrome/browser/chromeos/input_method/candidate_window.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 shortcut_label->SetText( 229 shortcut_label->SetText(
230 CreateShortcutText(i, lookup_table.orientation)); 230 CreateShortcutText(i, lookup_table.orientation));
231 shortcut_column_width = 231 shortcut_column_width =
232 std::max(shortcut_column_width, 232 std::max(shortcut_column_width,
233 wrapped_shortcut_label->GetPreferredSize().width()); 233 wrapped_shortcut_label->GetPreferredSize().width());
234 } 234 }
235 235
236 return shortcut_column_width; 236 return shortcut_column_width;
237 } 237 }
238 238
239 // Computes the page index. For instance, if the page size is 9, and the
240 // cursor is pointing to 13th candidate, the page index will be 1 (2nd
241 // page, as the index is zero-origin). Returns -1 on error.
242 int ComputePageIndex(const chromeos::InputMethodLookupTable& lookup_table) {
243 if (lookup_table.page_size > 0)
244 return lookup_table.cursor_absolute_index / lookup_table.page_size;
245 return -1;
246 }
247
239 // Computes candidate column width. 248 // Computes candidate column width.
240 int ComputeCandidateColumnWidth( 249 int ComputeCandidateColumnWidth(
241 const chromeos::InputMethodLookupTable& lookup_table) { 250 const chromeos::InputMethodLookupTable& lookup_table) {
242 int candidate_column_width = 0; 251 int candidate_column_width = 0;
243 scoped_ptr<views::Label> candidate_label( 252 scoped_ptr<views::Label> candidate_label(
244 CreateCandidateLabel(lookup_table.orientation)); 253 CreateCandidateLabel(lookup_table.orientation));
245 254
246 // Compute the start index of |lookup_table_|. 255 // Compute the start index of |lookup_table_|.
247 const int current_page_index = 256 const int current_page_index = ComputePageIndex(lookup_table);
248 lookup_table.cursor_absolute_index / lookup_table.page_size; 257 if (current_page_index < 0)
258 return 0;
249 const size_t start_from = current_page_index * lookup_table.page_size; 259 const size_t start_from = current_page_index * lookup_table.page_size;
250 260
251 // Compute the max width in candidate labels. 261 // Compute the max width in candidate labels.
252 // We'll create temporary candidate labels, and choose the largest width. 262 // We'll create temporary candidate labels, and choose the largest width.
253 for (size_t i = 0; i < lookup_table.candidates.size(); ++i) { 263 for (size_t i = 0; i < lookup_table.candidates.size(); ++i) {
254 const size_t index = start_from + i; 264 const size_t index = start_from + i;
255 265
256 candidate_label->SetText( 266 candidate_label->SetText(
257 UTF8ToWide(lookup_table.candidates[index])); 267 UTF8ToWide(lookup_table.candidates[index]));
258 candidate_column_width = 268 candidate_column_width =
259 std::max(candidate_column_width, 269 std::max(candidate_column_width,
260 candidate_label->GetPreferredSize().width()); 270 candidate_label->GetPreferredSize().width());
261 } 271 }
262 272
263 return candidate_column_width; 273 return candidate_column_width;
264 } 274 }
265 275
266 // Computes annotation column width. 276 // Computes annotation column width.
267 int ComputeAnnotationColumnWidth( 277 int ComputeAnnotationColumnWidth(
268 const chromeos::InputMethodLookupTable& lookup_table) { 278 const chromeos::InputMethodLookupTable& lookup_table) {
269 int annotation_column_width = 0; 279 int annotation_column_width = 0;
270 scoped_ptr<views::Label> annotation_label( 280 scoped_ptr<views::Label> annotation_label(
271 CreateAnnotationLabel(lookup_table.orientation)); 281 CreateAnnotationLabel(lookup_table.orientation));
272 282
273 // Compute the start index of |lookup_table_|. 283 // Compute the start index of |lookup_table_|.
274 const int current_page_index = 284 const int current_page_index = ComputePageIndex(lookup_table);
275 lookup_table.cursor_absolute_index / lookup_table.page_size; 285 if (current_page_index < 0)
286 return 0;
276 const size_t start_from = current_page_index * lookup_table.page_size; 287 const size_t start_from = current_page_index * lookup_table.page_size;
277 288
278 // Compute max width in annotation labels. 289 // Compute max width in annotation labels.
279 // We'll create temporary annotation labels, and choose the largest width. 290 // We'll create temporary annotation labels, and choose the largest width.
280 for (size_t i = 0; i < lookup_table.annotations.size(); ++i) { 291 for (size_t i = 0; i < lookup_table.annotations.size(); ++i) {
281 const size_t index = start_from + i; 292 const size_t index = start_from + i;
282 293
283 annotation_label->SetText( 294 annotation_label->SetText(
284 UTF8ToWide(lookup_table.annotations[index])); 295 UTF8ToWide(lookup_table.annotations[index]));
285 annotation_column_width = 296 annotation_column_width =
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 349
339 // Hides the auxiliary text. 350 // Hides the auxiliary text.
340 void HideAuxiliaryText(); 351 void HideAuxiliaryText();
341 352
342 // Shows the auxiliary text. 353 // Shows the auxiliary text.
343 void ShowAuxiliaryText(); 354 void ShowAuxiliaryText();
344 355
345 // Updates the auxiliary text. 356 // Updates the auxiliary text.
346 void UpdateAuxiliaryText(const std::string& utf8_text); 357 void UpdateAuxiliaryText(const std::string& utf8_text);
347 358
359 // Returns true if we should update candidate views in the window. For
360 // instance, if we are going to show the same candidates as before, we
361 // don't have to update candidate views. This happens when the user just
362 // moves the cursor in the same page in the candidate window.
363 bool ShouldUpdateCandidateViews(
364 const InputMethodLookupTable& previous_table,
365 const InputMethodLookupTable& current_table);
366
348 // Updates candidates of the candidate window from |lookup_table|. 367 // Updates candidates of the candidate window from |lookup_table|.
349 // Candidates are arranged per |orientation|. 368 // Candidates are arranged per |orientation|.
350 void UpdateCandidates(const InputMethodLookupTable& lookup_table); 369 void UpdateCandidates(const InputMethodLookupTable& lookup_table);
351 370
352 // Resizes the parent frame and schedules painting. This needs to be 371 // Resizes the parent frame and schedules painting. This needs to be
353 // called when the visible contents of the candidate window are 372 // called when the visible contents of the candidate window are
354 // modified. 373 // modified.
355 void ResizeAndSchedulePaint(); 374 void ResizeAndSchedulePaint();
356 375
357 // Returns the horizontal offset used for placing the vertical candidate 376 // Returns the horizontal offset used for placing the vertical candidate
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 ResizeAndSchedulePaint(); 789 ResizeAndSchedulePaint();
771 } 790 }
772 791
773 void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) { 792 void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) {
774 views::Label* target_label = ( 793 views::Label* target_label = (
775 lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? 794 lookup_table_.orientation == InputMethodLookupTable::kHorizontal ?
776 header_label_ : footer_label_); 795 header_label_ : footer_label_);
777 target_label->SetText(UTF8ToWide(utf8_text)); 796 target_label->SetText(UTF8ToWide(utf8_text));
778 } 797 }
779 798
799 bool CandidateWindowView::ShouldUpdateCandidateViews(
800 const InputMethodLookupTable& previous_table,
801 const InputMethodLookupTable& current_table) {
802 // Check if most table contents are identical.
803 if (previous_table.page_size == current_table.page_size &&
804 previous_table.orientation == current_table.orientation &&
805 previous_table.candidates == current_table.candidates &&
806 previous_table.labels == current_table.labels &&
807 previous_table.annotations == current_table.annotations &&
808 // Check if the page indexes are identical.
809 ComputePageIndex(previous_table) == ComputePageIndex(current_table)) {
810 // If all of the conditions are met, we don't have to update candidate
811 // views.
812 return false;
813 }
814 return true;
815 }
816
780 void CandidateWindowView::UpdateCandidates( 817 void CandidateWindowView::UpdateCandidates(
781 const InputMethodLookupTable& lookup_table) { 818 const InputMethodLookupTable& lookup_table) {
782 // Initialize candidate views if necessary. 819 const bool should_update = ShouldUpdateCandidateViews(lookup_table_,
783 MaybeInitializeCandidateViews(lookup_table); 820 lookup_table);
821 // Updating the candidate views is expensive. We'll skip this if possible.
822 if (should_update) {
823 // Initialize candidate views if necessary.
824 MaybeInitializeCandidateViews(lookup_table);
784 825
785 // In MaybeInitializeCandidateViews(), 826 // Compute the index of the current page.
786 // |lookup_table| values and |lookup_table_| values are compared, 827 if (lookup_table.page_size <= 0) {
787 // so this substitution is needed after the function. 828 LOG(ERROR) << "Invalid page size: " << lookup_table.page_size;
829 return;
830 }
831 current_page_index_ =
832 lookup_table.cursor_absolute_index / lookup_table.page_size;
833
834 // Update the candidates in the current page.
835 const size_t start_from = current_page_index_ * lookup_table.page_size;
836
837 // In some cases, engines send empty shortcut labels. For instance,
838 // ibus-mozc sends empty labels when they show suggestions. In this
839 // case, we should not show shortcut labels.
840 const bool no_shortcut_mode = (start_from < lookup_table.labels.size() &&
841 lookup_table.labels[start_from] == "");
842 for (size_t i = 0; i < candidate_views_.size(); ++i) {
843 const size_t index_in_page = i;
844 const size_t candidate_index = start_from + index_in_page;
845 CandidateView* candidate_view = candidate_views_[index_in_page];
846 // Set the shortcut text.
847 if (no_shortcut_mode) {
848 candidate_view->SetShortcutText(L"");
849 } else {
850 // At this moment, we don't use labels sent from engines for UX
851 // reasons. First, we want to show shortcut labels in empty rows
852 // (ex. show 6, 7, 8, ... in empty rows when the number of
853 // candidates is 5). Second, we want to add a period after each
854 // shortcut label when the candidate window is horizontal.
855 candidate_view->SetShortcutText(
856 CreateShortcutText(i, lookup_table.orientation));
857 }
858 // Set the candidate text.
859 if (candidate_index < lookup_table.candidates.size() &&
860 candidate_index < lookup_table.annotations.size()) {
861 candidate_view->SetCandidateText(
862 UTF8ToWide(lookup_table.candidates[candidate_index]));
863 candidate_view->SetAnnotationText(
864 UTF8ToWide(lookup_table.annotations[candidate_index]));
865 candidate_view->SetRowEnabled(true);
866 } else {
867 // Disable the empty row.
868 candidate_view->SetCandidateText(L"");
869 candidate_view->SetAnnotationText(L"");
870 candidate_view->SetRowEnabled(false);
871 }
872 }
873 }
satorux1 2010/12/01 09:25:32 Hmm, rietveld didn't do a good job for showing dif
788 lookup_table_ = lookup_table; 874 lookup_table_ = lookup_table;
789 875
790 // Compute the index of the current page. 876 // Select the current candidate in the page.
791 current_page_index_ = 877 const int current_candidate_in_page =
792 lookup_table.cursor_absolute_index / lookup_table.page_size;
793
794 // Update the candidates in the current page.
795 const size_t start_from = current_page_index_ * lookup_table.page_size;
796
797 // In some cases, engines send empty shortcut labels. For instance,
798 // ibus-mozc sends empty labels when they show suggestions. In this
799 // case, we should not show shortcut labels.
800 const bool no_shortcut_mode = (start_from < lookup_table_.labels.size() &&
801 lookup_table_.labels[start_from] == "");
802 for (size_t i = 0; i < candidate_views_.size(); ++i) {
803 const size_t index_in_page = i;
804 const size_t candidate_index = start_from + index_in_page;
805 CandidateView* candidate_view = candidate_views_[index_in_page];
806 // Set the shortcut text.
807 if (no_shortcut_mode) {
808 candidate_view->SetShortcutText(L"");
809 } else {
810 // At this moment, we don't use labels sent from engines for UX
811 // reasons. First, we want to show shortcut labels in empty rows
812 // (ex. show 6, 7, 8, ... in empty rows when the number of
813 // candidates is 5). Second, we want to add a period after each
814 // shortcut label when the candidate window is horizontal.
815 candidate_view->SetShortcutText(
816 CreateShortcutText(i, lookup_table_.orientation));
817 }
818 // Set the candidate text.
819 if (candidate_index < lookup_table_.candidates.size() &&
820 candidate_index < lookup_table_.annotations.size()) {
821 candidate_view->SetCandidateText(
822 UTF8ToWide(lookup_table_.candidates[candidate_index]));
823 candidate_view->SetAnnotationText(
824 UTF8ToWide(lookup_table_.annotations[candidate_index]));
825 candidate_view->SetRowEnabled(true);
826 } else {
827 // Disable the empty row.
828 candidate_view->SetCandidateText(L"");
829 candidate_view->SetAnnotationText(L"");
830 candidate_view->SetRowEnabled(false);
831 }
832 }
833
834 // Select the first candidate candidate in the page.
835 const int first_candidate_in_page =
836 lookup_table.cursor_absolute_index % lookup_table.page_size; 878 lookup_table.cursor_absolute_index % lookup_table.page_size;
837 SelectCandidateAt(first_candidate_in_page); 879 SelectCandidateAt(current_candidate_in_page);
838 } 880 }
839 881
840 void CandidateWindowView::MaybeInitializeCandidateViews( 882 void CandidateWindowView::MaybeInitializeCandidateViews(
841 const InputMethodLookupTable& lookup_table) { 883 const InputMethodLookupTable& lookup_table) {
842 const InputMethodLookupTable::Orientation orientation = 884 const InputMethodLookupTable::Orientation orientation =
843 lookup_table.orientation; 885 lookup_table.orientation;
844 const int page_size = lookup_table.page_size; 886 const int page_size = lookup_table.page_size;
845 887
846 // Current column width. 888 // Current column width.
847 int shortcut_column_width = 0; 889 int shortcut_column_width = 0;
848 int candidate_column_width = 0; 890 int candidate_column_width = 0;
849 int annotation_column_width = 0; 891 int annotation_column_width = 0;
850 892
851 // If orientation is horizontal, don't need to compute width, 893 // If orientation is horizontal, don't need to compute width,
852 // because each label is left aligned. 894 // because each label is left aligned.
853 if (orientation == InputMethodLookupTable::kVertical) { 895 if (orientation == InputMethodLookupTable::kVertical) {
854 shortcut_column_width = ComputeShortcutColumnWidth(lookup_table); 896 shortcut_column_width = ComputeShortcutColumnWidth(lookup_table);
855 candidate_column_width = ComputeCandidateColumnWidth(lookup_table); 897 candidate_column_width = ComputeCandidateColumnWidth(lookup_table);
856 annotation_column_width = ComputeAnnotationColumnWidth(lookup_table); 898 annotation_column_width = ComputeAnnotationColumnWidth(lookup_table);
857 } 899 }
858 900
859 // If the requested number of views matches the number of current views, and 901 // If the requested number of views matches the number of current views, and
860 // previous and current column width are same, just reuse these. 902 // previous and current column width are same, just reuse these.
903 //
904 // Note that the early exit logic is not only useful for improving
905 // performance, but also necessary for the horizontal candidate window
906 // to be redrawn properly. If we get rid of the logic, the horizontal
907 // candidate window won't get redrawn properly for some reason when
908 // there is no size change. You can test this by removing "return" here
909 // and type "ni" with Pinyin input method.
861 if (static_cast<int>(candidate_views_.size()) == page_size && 910 if (static_cast<int>(candidate_views_.size()) == page_size &&
862 lookup_table_.orientation == orientation && 911 lookup_table_.orientation == orientation &&
863 previous_shortcut_column_width_ == shortcut_column_width && 912 previous_shortcut_column_width_ == shortcut_column_width &&
864 previous_candidate_column_width_ == candidate_column_width && 913 previous_candidate_column_width_ == candidate_column_width &&
865 previous_annotation_column_width_ == annotation_column_width) { 914 previous_annotation_column_width_ == annotation_column_width) {
866 return; 915 return;
867 } 916 }
868 917
869 // Update the previous column widths. 918 // Update the previous column widths.
870 previous_shortcut_column_width_ = shortcut_column_width; 919 previous_shortcut_column_width_ = shortcut_column_width;
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
1204 DLOG(INFO) << "Ignored set_cursor_location signal to prevent window shake"; 1253 DLOG(INFO) << "Ignored set_cursor_location signal to prevent window shake";
1205 return; 1254 return;
1206 } 1255 }
1207 1256
1208 // Remember the cursor location. 1257 // Remember the cursor location.
1209 controller->set_cursor_location(gfx::Rect(x, y, width, height)); 1258 controller->set_cursor_location(gfx::Rect(x, y, width, height));
1210 // Move the window per the cursor location. 1259 // Move the window per the cursor location.
1211 controller->MoveCandidateWindow( 1260 controller->MoveCandidateWindow(
1212 controller->cursor_location(), 1261 controller->cursor_location(),
1213 controller->candidate_window_->GetHorizontalOffset()); 1262 controller->candidate_window_->GetHorizontalOffset());
1214 // The call is needed to ensure that the candidate window is redrawed 1263 // The call is needed to ensure that the candidate window is redrawn
1215 // properly after the cursor location is changed. 1264 // properly after the cursor location is changed.
1216 controller->candidate_window_->ResizeAndSchedulePaint(); 1265 controller->candidate_window_->ResizeAndSchedulePaint();
1217 } 1266 }
1218 1267
1219 void CandidateWindowController::Impl::OnUpdateAuxiliaryText( 1268 void CandidateWindowController::Impl::OnUpdateAuxiliaryText(
1220 void* input_method_library, 1269 void* input_method_library,
1221 const std::string& utf8_text, 1270 const std::string& utf8_text,
1222 bool visible) { 1271 bool visible) {
1223 CandidateWindowController::Impl* controller = 1272 CandidateWindowController::Impl* controller =
1224 static_cast<CandidateWindowController::Impl*>(input_method_library); 1273 static_cast<CandidateWindowController::Impl*>(input_method_library);
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 1330
1282 CandidateWindowController::~CandidateWindowController() { 1331 CandidateWindowController::~CandidateWindowController() {
1283 delete impl_; 1332 delete impl_;
1284 } 1333 }
1285 1334
1286 bool CandidateWindowController::Init() { 1335 bool CandidateWindowController::Init() {
1287 return impl_->Init(); 1336 return impl_->Init();
1288 } 1337 }
1289 1338
1290 } // namespace chromeos 1339 } // namespace chromeos
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698