| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011, Google Inc. All rights reserved. | 2 * Copyright (c) 2011, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| 11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
| 12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
| 13 * distribution. | 13 * distribution. |
| 14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
| 15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
| 16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
| 17 * | 17 * |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 |
| 30 #include "config.h" | 31 #include "config.h" |
| 31 #include "core/platform/chromium/PopupListBox.h" | 32 #include "core/platform/chromium/PopupListBox.h" |
| 32 | 33 |
| 33 #include <ctype.h> | |
| 34 #include <limits> | |
| 35 #include "CSSValueKeywords.h" | 34 #include "CSSValueKeywords.h" |
| 36 #include "RuntimeEnabledFeatures.h" | 35 #include "RuntimeEnabledFeatures.h" |
| 37 #include "core/platform/PlatformGestureEvent.h" | 36 #include "core/platform/PlatformGestureEvent.h" |
| 38 #include "core/platform/PlatformKeyboardEvent.h" | 37 #include "core/platform/PlatformKeyboardEvent.h" |
| 39 #include "core/platform/PlatformMouseEvent.h" | 38 #include "core/platform/PlatformMouseEvent.h" |
| 40 #include "core/platform/PlatformScreen.h" | 39 #include "core/platform/PlatformScreen.h" |
| 41 #include "core/platform/PlatformTouchEvent.h" | 40 #include "core/platform/PlatformTouchEvent.h" |
| 42 #include "core/platform/PlatformWheelEvent.h" | 41 #include "core/platform/PlatformWheelEvent.h" |
| 43 #include "core/platform/PopupMenuClient.h" | 42 #include "core/platform/PopupMenuClient.h" |
| 44 #include "core/platform/ScrollbarTheme.h" | 43 #include "core/platform/ScrollbarTheme.h" |
| 45 #include "core/platform/chromium/FramelessScrollViewClient.h" | 44 #include "core/platform/chromium/FramelessScrollViewClient.h" |
| 46 #include "core/platform/chromium/KeyboardCodes.h" | 45 #include "core/platform/chromium/KeyboardCodes.h" |
| 47 #include "core/platform/chromium/PopupContainer.h" | 46 #include "core/platform/chromium/PopupContainer.h" |
| 48 #include "core/platform/chromium/PopupMenuChromium.h" | 47 #include "core/platform/chromium/PopupMenuChromium.h" |
| 49 #include "core/platform/graphics/Font.h" | 48 #include "core/platform/graphics/Font.h" |
| 50 #include "core/platform/graphics/FontSelector.h" | 49 #include "core/platform/graphics/FontSelector.h" |
| 51 #include "core/platform/graphics/GraphicsContext.h" | 50 #include "core/platform/graphics/GraphicsContext.h" |
| 52 #include "core/platform/graphics/IntRect.h" | 51 #include "core/platform/graphics/IntRect.h" |
| 53 #include "core/platform/graphics/StringTruncator.h" | 52 #include "core/platform/graphics/StringTruncator.h" |
| 54 #include "core/platform/graphics/TextRun.h" | 53 #include "core/platform/graphics/TextRun.h" |
| 55 #include "core/rendering/RenderTheme.h" | 54 #include "core/rendering/RenderTheme.h" |
| 56 #include <wtf/CurrentTime.h> | 55 #include "wtf/ASCIICType.h" |
| 56 #include "wtf/CurrentTime.h" |
| 57 #include <limits> |
| 57 | 58 |
| 58 namespace WebCore { | 59 namespace WebCore { |
| 59 | 60 |
| 60 using namespace std; | 61 using namespace WTF::Unicode; |
| 61 using namespace WTF; | 62 |
| 62 using namespace Unicode; | 63 static const int labelToIconPadding = 5; |
| 64 // Padding height put at the top and bottom of each line. |
| 65 static const int autofillLinePaddingHeight = 3; |
| 66 const int PopupListBox::defaultMaxHeight = 500; |
| 67 static const int maxVisibleRows = 20; |
| 68 static const int minEndOfLinePadding = 2; |
| 69 static const int textToLabelPadding = 10; |
| 70 static const TimeStamp typeAheadTimeoutMs = 1000; |
| 63 | 71 |
| 64 PopupListBox::PopupListBox(PopupMenuClient* client, const PopupContainerSettings
& settings) | 72 PopupListBox::PopupListBox(PopupMenuClient* client, const PopupContainerSettings
& settings) |
| 65 : m_settings(settings) | 73 : m_settings(settings) |
| 66 , m_originalIndex(0) | 74 , m_originalIndex(0) |
| 67 , m_selectedIndex(0) | 75 , m_selectedIndex(0) |
| 68 , m_acceptedIndexOnAbandon(-1) | 76 , m_acceptedIndexOnAbandon(-1) |
| 69 , m_visibleRows(0) | 77 , m_visibleRows(0) |
| 70 , m_baseWidth(0) | 78 , m_baseWidth(0) |
| 71 , m_maxHeight(kMaxHeight) | 79 , m_maxHeight(defaultMaxHeight) |
| 72 , m_popupClient(client) | 80 , m_popupClient(client) |
| 73 , m_repeatingChar(0) | 81 , m_repeatingChar(0) |
| 74 , m_lastCharTime(0) | 82 , m_lastCharTime(0) |
| 75 , m_maxWindowWidth(std::numeric_limits<int>::max()) | 83 , m_maxWindowWidth(std::numeric_limits<int>::max()) |
| 76 { | 84 { |
| 77 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); | 85 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); |
| 78 } | 86 } |
| 79 | 87 |
| 80 bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) | 88 bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) |
| 81 { | 89 { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 { | 131 { |
| 124 if (m_capturingScrollbar) { | 132 if (m_capturingScrollbar) { |
| 125 m_capturingScrollbar->mouseUp(event); | 133 m_capturingScrollbar->mouseUp(event); |
| 126 m_capturingScrollbar = 0; | 134 m_capturingScrollbar = 0; |
| 127 return true; | 135 return true; |
| 128 } | 136 } |
| 129 | 137 |
| 130 if (!isPointInBounds(event.position())) | 138 if (!isPointInBounds(event.position())) |
| 131 return true; | 139 return true; |
| 132 | 140 |
| 133 // Need to check before calling acceptIndex(), because m_popupClient might b
e removed in acceptIndex() calling because of event handler. | 141 // Need to check before calling acceptIndex(), because m_popupClient might |
| 142 // be removed in acceptIndex() calling because of event handler. |
| 134 bool isSelectPopup = m_popupClient->menuStyle().menuType() == PopupMenuStyle
::SelectPopup; | 143 bool isSelectPopup = m_popupClient->menuStyle().menuType() == PopupMenuStyle
::SelectPopup; |
| 135 if (acceptIndex(pointToRowIndex(event.position())) && m_focusedNode && isSel
ectPopup) { | 144 if (acceptIndex(pointToRowIndex(event.position())) && m_focusedNode && isSel
ectPopup) { |
| 136 m_focusedNode->dispatchMouseEvent(event, eventNames().mouseupEvent); | 145 m_focusedNode->dispatchMouseEvent(event, eventNames().mouseupEvent); |
| 137 m_focusedNode->dispatchMouseEvent(event, eventNames().clickEvent); | 146 m_focusedNode->dispatchMouseEvent(event, eventNames().clickEvent); |
| 138 | 147 |
| 139 // Clear m_focusedNode here, because we cannot clear in hidePopup() whic
h is called before dispatchMouseEvent() is called. | 148 // Clear m_focusedNode here, because we cannot clear in hidePopup() |
| 149 // which is called before dispatchMouseEvent() is called. |
| 140 m_focusedNode = 0; | 150 m_focusedNode = 0; |
| 141 } | 151 } |
| 142 | 152 |
| 143 return true; | 153 return true; |
| 144 } | 154 } |
| 145 | 155 |
| 146 bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event) | 156 bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event) |
| 147 { | 157 { |
| 148 if (!isPointInBounds(event.position())) { | 158 if (!isPointInBounds(event.position())) { |
| 149 abandon(); | 159 abandon(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 case VKEY_RETURN: | 217 case VKEY_RETURN: |
| 208 if (m_selectedIndex == -1) { | 218 if (m_selectedIndex == -1) { |
| 209 hidePopup(); | 219 hidePopup(); |
| 210 // Don't eat the enter if nothing is selected. | 220 // Don't eat the enter if nothing is selected. |
| 211 return false; | 221 return false; |
| 212 } | 222 } |
| 213 acceptIndex(m_selectedIndex); // may delete this | 223 acceptIndex(m_selectedIndex); // may delete this |
| 214 return true; | 224 return true; |
| 215 case VKEY_UP: | 225 case VKEY_UP: |
| 216 case VKEY_DOWN: | 226 case VKEY_DOWN: |
| 217 // We have to forward only shift + up combination to focused node when a
utofill popup. | 227 // We have to forward only shift + up combination to focused node when |
| 218 // Because all characters from the cursor to the start of the text area
should selected when you press shift + up arrow. | 228 // autofill popup. Because all characters from the cursor to the start |
| 229 // of the text area should selected when you press shift + up arrow. |
| 219 // shift + down should be the similar way to shift + up. | 230 // shift + down should be the similar way to shift + up. |
| 220 if (event.modifiers() && m_popupClient->menuStyle().menuType() == PopupM
enuStyle::AutofillPopup) | 231 if (event.modifiers() && m_popupClient->menuStyle().menuType() == PopupM
enuStyle::AutofillPopup) |
| 221 m_focusedNode->dispatchKeyEvent(event); | 232 m_focusedNode->dispatchKeyEvent(event); |
| 222 else if (event.windowsVirtualKeyCode() == VKEY_UP) | 233 else if (event.windowsVirtualKeyCode() == VKEY_UP) |
| 223 selectPreviousRow(); | 234 selectPreviousRow(); |
| 224 else | 235 else |
| 225 selectNextRow(); | 236 selectNextRow(); |
| 226 break; | 237 break; |
| 227 case VKEY_PRIOR: | 238 case VKEY_PRIOR: |
| 228 adjustSelectedIndex(-m_visibleRows); | 239 adjustSelectedIndex(-m_visibleRows); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 return parent() ? parent()->hostWindow() : 0; | 291 return parent() ? parent()->hostWindow() : 0; |
| 281 } | 292 } |
| 282 | 293 |
| 283 // From HTMLSelectElement.cpp | 294 // From HTMLSelectElement.cpp |
| 284 static String stripLeadingWhiteSpace(const String& string) | 295 static String stripLeadingWhiteSpace(const String& string) |
| 285 { | 296 { |
| 286 int length = string.length(); | 297 int length = string.length(); |
| 287 int i; | 298 int i; |
| 288 for (i = 0; i < length; ++i) | 299 for (i = 0; i < length; ++i) |
| 289 if (string[i] != noBreakSpace | 300 if (string[i] != noBreakSpace |
| 290 && (string[i] <= 0x7F ? !isspace(string[i]) : (direction(string[i])
!= WhiteSpaceNeutral))) | 301 && (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string
[i]) != WhiteSpaceNeutral))) |
| 291 break; | 302 break; |
| 292 | 303 |
| 293 return string.substring(i, length - i); | 304 return string.substring(i, length - i); |
| 294 } | 305 } |
| 295 | 306 |
| 296 // From HTMLSelectElement.cpp, with modifications | 307 // From HTMLSelectElement.cpp, with modifications |
| 297 void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event) | 308 void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event) |
| 298 { | 309 { |
| 299 TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f); | 310 TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f); |
| 300 TimeStamp delta = now - m_lastCharTime; | 311 TimeStamp delta = now - m_lastCharTime; |
| 301 | 312 |
| 302 // Reset the time when user types in a character. The time gap between | 313 // Reset the time when user types in a character. The time gap between |
| 303 // last character and the current character is used to indicate whether | 314 // last character and the current character is used to indicate whether |
| 304 // user typed in a string or just a character as the search prefix. | 315 // user typed in a string or just a character as the search prefix. |
| 305 m_lastCharTime = now; | 316 m_lastCharTime = now; |
| 306 | 317 |
| 307 UChar c = event.windowsVirtualKeyCode(); | 318 UChar c = event.windowsVirtualKeyCode(); |
| 308 | 319 |
| 309 String prefix; | 320 String prefix; |
| 310 int searchStartOffset = 1; | 321 int searchStartOffset = 1; |
| 311 if (delta > kTypeAheadTimeoutMs) { | 322 if (delta > typeAheadTimeoutMs) { |
| 312 m_typedString = prefix = String(&c, 1); | 323 m_typedString = prefix = String(&c, 1); |
| 313 m_repeatingChar = c; | 324 m_repeatingChar = c; |
| 314 } else { | 325 } else { |
| 315 m_typedString.append(c); | 326 m_typedString.append(c); |
| 316 | 327 |
| 317 if (c == m_repeatingChar) | 328 if (c == m_repeatingChar) { |
| 318 // The user is likely trying to cycle through all the items starting
with this character, so just search on the character | 329 // The user is likely trying to cycle through all the items starting |
| 330 // with this character, so just search on the character. |
| 319 prefix = String(&c, 1); | 331 prefix = String(&c, 1); |
| 320 else { | 332 } else { |
| 321 m_repeatingChar = 0; | 333 m_repeatingChar = 0; |
| 322 prefix = m_typedString; | 334 prefix = m_typedString; |
| 323 searchStartOffset = 0; | 335 searchStartOffset = 0; |
| 324 } | 336 } |
| 325 } | 337 } |
| 326 | 338 |
| 327 // Compute a case-folded copy of the prefix string before beginning the sear
ch for | 339 // Compute a case-folded copy of the prefix string before beginning the |
| 328 // a matching element. This code uses foldCase to work around the fact that | 340 // search for a matching element. This code uses foldCase to work around the |
| 329 // String::startWith does not fold non-ASCII characters. This code can be ch
anged | 341 // fact that String::startWith does not fold non-ASCII characters. This code |
| 330 // to use startWith once that is fixed. | 342 // can be changed to use startWith once that is fixed. |
| 331 String prefixWithCaseFolded(prefix.foldCase()); | 343 String prefixWithCaseFolded(prefix.foldCase()); |
| 332 int itemCount = numItems(); | 344 int itemCount = numItems(); |
| 333 int index = (max(0, m_selectedIndex) + searchStartOffset) % itemCount; | 345 int index = (max(0, m_selectedIndex) + searchStartOffset) % itemCount; |
| 334 for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) { | 346 for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) { |
| 335 if (!isSelectableItem(index)) | 347 if (!isSelectableItem(index)) |
| 336 continue; | 348 continue; |
| 337 | 349 |
| 338 if (stripLeadingWhiteSpace(m_items[index]->label).foldCase().startsWith(
prefixWithCaseFolded)) { | 350 if (stripLeadingWhiteSpace(m_items[index]->label).foldCase().startsWith(
prefixWithCaseFolded)) { |
| 339 selectIndex(index); | 351 selectIndex(index); |
| 340 return; | 352 return; |
| 341 } | 353 } |
| 342 } | 354 } |
| 343 } | 355 } |
| 344 | 356 |
| 345 void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect) | 357 void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect) |
| 346 { | 358 { |
| 347 // adjust coords for scrolled frame | 359 // Adjust coords for scrolled frame. |
| 348 IntRect r = intersection(rect, frameRect()); | 360 IntRect r = intersection(rect, frameRect()); |
| 349 int tx = x() - scrollX(); | 361 int tx = x() - scrollX(); |
| 350 int ty = y() - scrollY(); | 362 int ty = y() - scrollY(); |
| 351 | 363 |
| 352 r.move(-tx, -ty); | 364 r.move(-tx, -ty); |
| 353 | 365 |
| 354 // set clip rect to match revised damage rect | 366 // Set clip rect to match revised damage rect. |
| 355 gc->save(); | 367 gc->save(); |
| 356 gc->translate(static_cast<float>(tx), static_cast<float>(ty)); | 368 gc->translate(static_cast<float>(tx), static_cast<float>(ty)); |
| 357 gc->clip(r); | 369 gc->clip(r); |
| 358 | 370 |
| 359 // FIXME: Can we optimize scrolling to not require repainting the entire | 371 // FIXME: Can we optimize scrolling to not require repainting the entire |
| 360 // window? Should we? | 372 // window? Should we? |
| 361 for (int i = 0; i < numItems(); ++i) | 373 for (int i = 0; i < numItems(); ++i) |
| 362 paintRow(gc, r, i); | 374 paintRow(gc, r, i); |
| 363 | 375 |
| 364 // Special case for an empty popup. | 376 // Special case for an empty popup. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 // Prepare text to be drawn. | 458 // Prepare text to be drawn. |
| 447 String itemText = m_popupClient->itemText(rowIndex); | 459 String itemText = m_popupClient->itemText(rowIndex); |
| 448 String itemLabel = m_popupClient->itemLabel(rowIndex); | 460 String itemLabel = m_popupClient->itemLabel(rowIndex); |
| 449 String itemIcon = m_popupClient->itemIcon(rowIndex); | 461 String itemIcon = m_popupClient->itemIcon(rowIndex); |
| 450 if (m_settings.restrictWidthOfListBox) { // Truncate strings to fit in. | 462 if (m_settings.restrictWidthOfListBox) { // Truncate strings to fit in. |
| 451 // FIXME: We should leftTruncate for the rtl case. | 463 // FIXME: We should leftTruncate for the rtl case. |
| 452 // StringTruncator::leftTruncate would have to be implemented. | 464 // StringTruncator::leftTruncate would have to be implemented. |
| 453 String str = StringTruncator::rightTruncate(itemText, maxWidth, itemFont
); | 465 String str = StringTruncator::rightTruncate(itemText, maxWidth, itemFont
); |
| 454 if (str != itemText) { | 466 if (str != itemText) { |
| 455 itemText = str; | 467 itemText = str; |
| 456 // Don't display the label or icon, we already don't have enough roo
m for the item text. | 468 // Don't display the label or icon, we already don't have enough |
| 469 // room for the item text. |
| 457 itemLabel = ""; | 470 itemLabel = ""; |
| 458 itemIcon = ""; | 471 itemIcon = ""; |
| 459 } else if (!itemLabel.isEmpty()) { | 472 } else if (!itemLabel.isEmpty()) { |
| 460 int availableWidth = maxWidth - kTextToLabelPadding - | 473 int availableWidth = maxWidth - textToLabelPadding - StringTruncator
::width(itemText, itemFont); |
| 461 StringTruncator::width(itemText, itemFont); | |
| 462 itemLabel = StringTruncator::rightTruncate(itemLabel, availableWidth
, itemFont); | 474 itemLabel = StringTruncator::rightTruncate(itemLabel, availableWidth
, itemFont); |
| 463 } | 475 } |
| 464 } | 476 } |
| 465 | 477 |
| 466 // Prepare the directionality to draw text. | 478 // Prepare the directionality to draw text. |
| 467 TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, style.textD
irection(), style.hasTextDirectionOverride()); | 479 TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, style.textD
irection(), style.hasTextDirectionOverride()); |
| 468 // If the text is right-to-left, make it right-aligned by adjusting its | 480 // If the text is right-to-left, make it right-aligned by adjusting its |
| 469 // beginning position. | 481 // beginning position. |
| 470 if (rightAligned) | 482 if (rightAligned) |
| 471 textX += maxWidth - itemFont.width(textRun); | 483 textX += maxWidth - itemFont.width(textRun); |
| 472 | 484 |
| 473 // Draw the item text. | 485 // Draw the item text. |
| 474 int textY = rowRect.y() + itemFont.fontMetrics().ascent() + (rowRect.height(
) - itemFont.fontMetrics().height()) / 2; | 486 int textY = rowRect.y() + itemFont.fontMetrics().ascent() + (rowRect.height(
) - itemFont.fontMetrics().height()) / 2; |
| 475 TextRunPaintInfo textRunPaintInfo(textRun); | 487 TextRunPaintInfo textRunPaintInfo(textRun); |
| 476 textRunPaintInfo.bounds = rowRect; | 488 textRunPaintInfo.bounds = rowRect; |
| 477 gc->drawBidiText(itemFont, textRunPaintInfo, IntPoint(textX, textY)); | 489 gc->drawBidiText(itemFont, textRunPaintInfo, IntPoint(textX, textY)); |
| 478 | 490 |
| 479 // We are using the left padding as the right padding includes room for the
scroll-bar which | 491 // We are using the left padding as the right padding includes room for the
scroll-bar which |
| 480 // does not show in this case. | 492 // does not show in this case. |
| 481 int rightPadding = max<int>(0, m_popupClient->clientPaddingLeft() - m_popupC
lient->clientInsetLeft()); | 493 int rightPadding = max<int>(0, m_popupClient->clientPaddingLeft() - m_popupC
lient->clientInsetLeft()); |
| 482 int remainingWidth = rowRect.width() - rightPadding; | 494 int remainingWidth = rowRect.width() - rightPadding; |
| 483 | 495 |
| 484 // Draw the icon if applicable. | 496 // Draw the icon if applicable. |
| 485 RefPtr<Image> image(Image::loadPlatformResource(itemIcon.utf8().data())); | 497 RefPtr<Image> image(Image::loadPlatformResource(itemIcon.utf8().data())); |
| 486 if (image && !image->isNull()) { | 498 if (image && !image->isNull()) { |
| 487 IntRect imageRect = image->rect(); | 499 IntRect imageRect = image->rect(); |
| 488 remainingWidth -= (imageRect.width() + kLabelToIconPadding); | 500 remainingWidth -= (imageRect.width() + labelToIconPadding); |
| 489 imageRect.setX(rowRect.width() - rightPadding - imageRect.width()); | 501 imageRect.setX(rowRect.width() - rightPadding - imageRect.width()); |
| 490 imageRect.setY(rowRect.y() + (rowRect.height() - imageRect.height()) / 2
); | 502 imageRect.setY(rowRect.y() + (rowRect.height() - imageRect.height()) / 2
); |
| 491 gc->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect); | 503 gc->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect); |
| 492 } | 504 } |
| 493 | 505 |
| 494 // Draw the the label if applicable. | 506 // Draw the the label if applicable. |
| 495 if (itemLabel.isEmpty()) | 507 if (itemLabel.isEmpty()) |
| 496 return; | 508 return; |
| 497 | 509 |
| 498 // Autofill label is 0.9 smaller than regular font size. | 510 // Autofill label is 0.9 smaller than regular font size. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 // Separator row height is the same size as itself. | 641 // Separator row height is the same size as itself. |
| 630 if (m_popupClient->itemIsSeparator(index)) | 642 if (m_popupClient->itemIsSeparator(index)) |
| 631 return max(separatorHeight, minimumHeight); | 643 return max(separatorHeight, minimumHeight); |
| 632 | 644 |
| 633 String icon = m_popupClient->itemIcon(index); | 645 String icon = m_popupClient->itemIcon(index); |
| 634 RefPtr<Image> image(Image::loadPlatformResource(icon.utf8().data())); | 646 RefPtr<Image> image(Image::loadPlatformResource(icon.utf8().data())); |
| 635 | 647 |
| 636 int fontHeight = getRowFont(index).fontMetrics().height(); | 648 int fontHeight = getRowFont(index).fontMetrics().height(); |
| 637 int iconHeight = (image && !image->isNull()) ? image->rect().height() : 0; | 649 int iconHeight = (image && !image->isNull()) ? image->rect().height() : 0; |
| 638 | 650 |
| 639 int linePaddingHeight = m_popupClient->menuStyle().menuType() == PopupMenuSt
yle::AutofillPopup ? kLinePaddingHeight : 0; | 651 int linePaddingHeight = m_popupClient->menuStyle().menuType() == PopupMenuSt
yle::AutofillPopup ? autofillLinePaddingHeight : 0; |
| 640 int calculatedRowHeight = max(fontHeight, iconHeight) + linePaddingHeight *
2; | 652 int calculatedRowHeight = max(fontHeight, iconHeight) + linePaddingHeight *
2; |
| 641 return max(calculatedRowHeight, minimumHeight); | 653 return max(calculatedRowHeight, minimumHeight); |
| 642 } | 654 } |
| 643 | 655 |
| 644 IntRect PopupListBox::getRowBounds(int index) | 656 IntRect PopupListBox::getRowBounds(int index) |
| 645 { | 657 { |
| 646 if (index < 0) | 658 if (index < 0) |
| 647 return IntRect(0, 0, visibleWidth(), getRowHeight(index)); | 659 return IntRect(0, 0, visibleWidth(), getRowHeight(index)); |
| 648 | 660 |
| 649 return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(inde
x)); | 661 return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(inde
x)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 } | 727 } |
| 716 | 728 |
| 717 // No row is selected, jump to the last item. | 729 // No row is selected, jump to the last item. |
| 718 selectIndex(numItems() - 1); | 730 selectIndex(numItems() - 1); |
| 719 scrollToRevealSelection(); | 731 scrollToRevealSelection(); |
| 720 } | 732 } |
| 721 | 733 |
| 722 void PopupListBox::adjustSelectedIndex(int delta) | 734 void PopupListBox::adjustSelectedIndex(int delta) |
| 723 { | 735 { |
| 724 int targetIndex = m_selectedIndex + delta; | 736 int targetIndex = m_selectedIndex + delta; |
| 725 targetIndex = min(max(targetIndex, 0), numItems() - 1); | 737 targetIndex = std::min(std::max(targetIndex, 0), numItems() - 1); |
| 726 if (!isSelectableItem(targetIndex)) { | 738 if (!isSelectableItem(targetIndex)) { |
| 727 // We didn't land on an option. Try to find one. | 739 // We didn't land on an option. Try to find one. |
| 728 // We try to select the closest index to target, prioritizing any in | 740 // We try to select the closest index to target, prioritizing any in |
| 729 // the range [current, target]. | 741 // the range [current, target]. |
| 730 | 742 |
| 731 int dir = delta > 0 ? 1 : -1; | 743 int dir = delta > 0 ? 1 : -1; |
| 732 int testIndex = m_selectedIndex; | 744 int testIndex = m_selectedIndex; |
| 733 int bestIndex = m_selectedIndex; | 745 int bestIndex = m_selectedIndex; |
| 734 bool passedTarget = false; | 746 bool passedTarget = false; |
| 735 while (testIndex >= 0 && testIndex < numItems()) { | 747 while (testIndex >= 0 && testIndex < numItems()) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 Font itemFont = getRowFont(i); | 831 Font itemFont = getRowFont(i); |
| 820 String text = m_popupClient->itemText(i); | 832 String text = m_popupClient->itemText(i); |
| 821 String label = m_popupClient->itemLabel(i); | 833 String label = m_popupClient->itemLabel(i); |
| 822 String icon = m_popupClient->itemIcon(i); | 834 String icon = m_popupClient->itemIcon(i); |
| 823 RefPtr<Image> iconImage(Image::loadPlatformResource(icon.utf8().data()))
; | 835 RefPtr<Image> iconImage(Image::loadPlatformResource(icon.utf8().data()))
; |
| 824 int width = 0; | 836 int width = 0; |
| 825 if (!text.isEmpty()) | 837 if (!text.isEmpty()) |
| 826 width = itemFont.width(TextRun(text)); | 838 width = itemFont.width(TextRun(text)); |
| 827 if (!label.isEmpty()) { | 839 if (!label.isEmpty()) { |
| 828 if (width > 0) | 840 if (width > 0) |
| 829 width += kTextToLabelPadding; | 841 width += textToLabelPadding; |
| 830 width += itemFont.width(TextRun(label)); | 842 width += itemFont.width(TextRun(label)); |
| 831 } | 843 } |
| 832 if (iconImage && !iconImage->isNull()) { | 844 if (iconImage && !iconImage->isNull()) { |
| 833 if (width > 0) | 845 if (width > 0) |
| 834 width += kLabelToIconPadding; | 846 width += labelToIconPadding; |
| 835 width += iconImage->rect().width(); | 847 width += iconImage->rect().width(); |
| 836 } | 848 } |
| 837 | 849 |
| 838 baseWidth = max(baseWidth, width); | 850 baseWidth = max(baseWidth, width); |
| 839 // FIXME: http://b/1210481 We should get the padding of individual optio
n elements. | 851 // FIXME: http://b/1210481 We should get the padding of individual |
| 852 // option elements. |
| 840 paddingWidth = max<int>(paddingWidth, | 853 paddingWidth = max<int>(paddingWidth, |
| 841 m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRig
ht()); | 854 m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRig
ht()); |
| 842 lineEndPaddingWidth = max<int>(lineEndPaddingWidth, | 855 lineEndPaddingWidth = max<int>(lineEndPaddingWidth, |
| 843 isRightAligned ? m_popupClient->clientPaddingLeft() : m_popupClient-
>clientPaddingRight()); | 856 isRightAligned ? m_popupClient->clientPaddingLeft() : m_popupClient-
>clientPaddingRight()); |
| 844 } | 857 } |
| 845 | 858 |
| 846 // Calculate scroll bar width. | 859 // Calculate scroll bar width. |
| 847 int windowHeight = 0; | 860 int windowHeight = 0; |
| 848 m_visibleRows = min(numItems(), kMaxVisibleRows); | 861 m_visibleRows = std::min(numItems(), maxVisibleRows); |
| 849 | 862 |
| 850 for (int i = 0; i < m_visibleRows; ++i) { | 863 for (int i = 0; i < m_visibleRows; ++i) { |
| 851 int rowHeight = getRowHeight(i); | 864 int rowHeight = getRowHeight(i); |
| 852 | 865 |
| 853 // Only clip the window height for non-Mac platforms. | 866 // Only clip the window height for non-Mac platforms. |
| 854 if (windowHeight + rowHeight > m_maxHeight) { | 867 if (windowHeight + rowHeight > m_maxHeight) { |
| 855 m_visibleRows = i; | 868 m_visibleRows = i; |
| 856 break; | 869 break; |
| 857 } | 870 } |
| 858 | 871 |
| 859 windowHeight += rowHeight; | 872 windowHeight += rowHeight; |
| 860 } | 873 } |
| 861 | 874 |
| 862 // Set our widget and scrollable contents sizes. | 875 // Set our widget and scrollable contents sizes. |
| 863 int scrollbarWidth = 0; | 876 int scrollbarWidth = 0; |
| 864 if (m_visibleRows < numItems()) { | 877 if (m_visibleRows < numItems()) { |
| 865 scrollbarWidth = ScrollbarTheme::theme()->scrollbarThickness(); | 878 scrollbarWidth = ScrollbarTheme::theme()->scrollbarThickness(); |
| 866 | 879 |
| 867 // Use kMinEndOfLinePadding when there is a scrollbar so that we use | 880 // Use minEndOfLinePadding when there is a scrollbar so that we use |
| 868 // as much as (lineEndPaddingWidth - kMinEndOfLinePadding) padding | 881 // as much as (lineEndPaddingWidth - minEndOfLinePadding) padding |
| 869 // space for scrollbar and allow user to use CSS padding to make the | 882 // space for scrollbar and allow user to use CSS padding to make the |
| 870 // popup listbox align with the select element. | 883 // popup listbox align with the select element. |
| 871 paddingWidth = paddingWidth - lineEndPaddingWidth + kMinEndOfLinePadding
; | 884 paddingWidth = paddingWidth - lineEndPaddingWidth + minEndOfLinePadding; |
| 872 } | 885 } |
| 873 | 886 |
| 874 int windowWidth; | 887 int windowWidth; |
| 875 int contentWidth; | 888 int contentWidth; |
| 876 if (m_settings.restrictWidthOfListBox) { | 889 if (m_settings.restrictWidthOfListBox) { |
| 877 windowWidth = m_baseWidth; | 890 windowWidth = m_baseWidth; |
| 878 contentWidth = m_baseWidth - scrollbarWidth; | 891 contentWidth = m_baseWidth - scrollbarWidth; |
| 879 } else { | 892 } else { |
| 880 windowWidth = baseWidth + scrollbarWidth + paddingWidth; | 893 windowWidth = baseWidth + scrollbarWidth + paddingWidth; |
| 881 if (windowWidth > m_maxWindowWidth) { | 894 if (windowWidth > m_maxWindowWidth) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 { | 926 { |
| 914 return numItems() && IntRect(0, 0, width(), height()).contains(point); | 927 return numItems() && IntRect(0, 0, width(), height()).contains(point); |
| 915 } | 928 } |
| 916 | 929 |
| 917 int PopupListBox::popupContentHeight() const | 930 int PopupListBox::popupContentHeight() const |
| 918 { | 931 { |
| 919 return height(); | 932 return height(); |
| 920 } | 933 } |
| 921 | 934 |
| 922 } // namespace WebCore | 935 } // namespace WebCore |
| OLD | NEW |