OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 3 * |
| 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions |
| 6 * are met: |
| 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright |
| 11 * notice, this list of conditions and the following disclaimer in the |
| 12 * documentation and/or other materials provided with the distribution. |
| 13 * |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ |
| 25 |
| 26 #include "config.h" |
| 27 #include "web/PopupMenuImpl.h" |
| 28 |
| 29 #include "core/HTMLNames.h" |
| 30 #include "core/css/CSSFontSelector.h" |
| 31 #include "core/dom/StyleEngine.h" |
| 32 #include "core/frame/FrameView.h" |
| 33 #include "core/html/HTMLHRElement.h" |
| 34 #include "core/html/HTMLOptGroupElement.h" |
| 35 #include "core/html/HTMLOptionElement.h" |
| 36 #include "core/page/PagePopup.h" |
| 37 #include "platform/geometry/IntRect.h" |
| 38 #include "public/platform/Platform.h" |
| 39 #include "public/web/WebColorChooser.h" |
| 40 #include "web/ChromeClientImpl.h" |
| 41 #include "web/WebViewImpl.h" |
| 42 |
| 43 namespace blink { |
| 44 |
| 45 class PopupMenuCSSFontSelector : public CSSFontSelector { |
| 46 public: |
| 47 static PassRefPtr<PopupMenuCSSFontSelector> create(Document* document, CSSFo
ntSelector* ownerFontSelector) |
| 48 { |
| 49 return adoptRefWillBeNoop(new PopupMenuCSSFontSelector(document, ownerFo
ntSelector)); |
| 50 } |
| 51 |
| 52 // We don't override willUseFontData() for now because the old PopupListBox |
| 53 // only worked with fonts loaded when opening the popup. |
| 54 virtual PassRefPtr<FontData> getFontData(const FontDescription&, const Atomi
cString&) override; |
| 55 |
| 56 private: |
| 57 PopupMenuCSSFontSelector(Document* document, CSSFontSelector* ownerFontSelec
tor) |
| 58 : CSSFontSelector(document) |
| 59 , m_ownerFontSelector(ownerFontSelector) { } |
| 60 RefPtrWillBeMember<CSSFontSelector> m_ownerFontSelector; |
| 61 }; |
| 62 |
| 63 PassRefPtr<FontData> PopupMenuCSSFontSelector::getFontData(const FontDescription
& description, const AtomicString& name) |
| 64 { |
| 65 return m_ownerFontSelector->getFontData(description, name); |
| 66 } |
| 67 |
| 68 PassRefPtrWillBeRawPtr<PopupMenuImpl> PopupMenuImpl::create(ChromeClientImpl* ch
romeClient, PopupMenuClient* client) |
| 69 { |
| 70 return adoptRefWillBeNoop(new PopupMenuImpl(chromeClient, client)); |
| 71 } |
| 72 |
| 73 PopupMenuImpl::PopupMenuImpl(ChromeClientImpl* chromeClient, PopupMenuClient* cl
ient) |
| 74 : m_chromeClient(chromeClient) |
| 75 , m_client(client) |
| 76 , m_popup(0) |
| 77 { |
| 78 } |
| 79 |
| 80 PopupMenuImpl::~PopupMenuImpl() |
| 81 { |
| 82 closePopup(); |
| 83 } |
| 84 |
| 85 IntSize PopupMenuImpl::contentSize() |
| 86 { |
| 87 return IntSize(0, 0); |
| 88 } |
| 89 |
| 90 void PopupMenuImpl::writeDocument(SharedBuffer* data) |
| 91 { |
| 92 IntRect anchorRectInScreen = m_chromeClient->rootViewToScreen(m_client->elem
entRectRelativeToRootView()); |
| 93 |
| 94 PagePopupClient::addString("<!DOCTYPE html><head><meta charset='UTF-8'><styl
e>\n", data); |
| 95 data->append(Platform::current()->loadResource("pickerCommon.css")); |
| 96 data->append(Platform::current()->loadResource("listPicker.css")); |
| 97 PagePopupClient::addString("</style></head><body><div id=main>Loading...</di
v><script>\n" |
| 98 "window.dialogArguments = {\n", data); |
| 99 addProperty("selectedIndex", m_client->selectedIndex(), data); |
| 100 PagePopupClient::addString("children: [\n", data); |
| 101 for (HTMLElement& child : Traversal<HTMLElement>::childrenOf(ownerElement())
) { |
| 102 if (isHTMLOptionElement(child)) |
| 103 addOption(toHTMLOptionElement(child), data); |
| 104 if (isHTMLOptGroupElement(child)) |
| 105 addOptGroup(toHTMLOptGroupElement(child), data); |
| 106 if (isHTMLHRElement(child)) |
| 107 addSeparator(toHTMLHRElement(child), data); |
| 108 } |
| 109 PagePopupClient::addString("],\n", data); |
| 110 addProperty("anchorRectInScreen", anchorRectInScreen, data); |
| 111 PagePopupClient::addString("};\n", data); |
| 112 data->append(Platform::current()->loadResource("pickerCommon.js")); |
| 113 data->append(Platform::current()->loadResource("listPicker.js")); |
| 114 PagePopupClient::addString("</script></body>\n", data); |
| 115 } |
| 116 |
| 117 const char* fontWeightToString(FontWeight weight) |
| 118 { |
| 119 switch (weight) { |
| 120 case FontWeight100: |
| 121 return "100"; |
| 122 case FontWeight200: |
| 123 return "200"; |
| 124 case FontWeight300: |
| 125 return "300"; |
| 126 case FontWeight400: |
| 127 return "400"; |
| 128 case FontWeight500: |
| 129 return "500"; |
| 130 case FontWeight600: |
| 131 return "600"; |
| 132 case FontWeight700: |
| 133 return "700"; |
| 134 case FontWeight800: |
| 135 return "800"; |
| 136 case FontWeight900: |
| 137 return "900"; |
| 138 } |
| 139 } |
| 140 |
| 141 void PopupMenuImpl::addElementStyle(HTMLElement& element, SharedBuffer* data) |
| 142 { |
| 143 RenderStyle* style = m_client->renderStyleForItem(element); |
| 144 ASSERT(style); |
| 145 PagePopupClient::addString("style: {\n", data); |
| 146 addProperty("color", style->visitedDependentColor(CSSPropertyColor).serializ
ed(), data); |
| 147 addProperty("backgroundColor", style->visitedDependentColor(CSSPropertyBackg
roundColor).serialized(), data); |
| 148 const FontDescription& fontDescription = style->font().fontDescription(); |
| 149 addProperty("fontSize", fontDescription.computedPixelSize(), data); |
| 150 addProperty("fontWeight", String(fontWeightToString(fontDescription.weight()
)), data); |
| 151 PagePopupClient::addString("fontFamily: [\n", data); |
| 152 for (const FontFamily* f = &fontDescription.family(); f; f = f->next()) { |
| 153 addJavaScriptString(f->family().string(), data); |
| 154 if (f->next()) |
| 155 PagePopupClient::addString(",\n", data); |
| 156 } |
| 157 PagePopupClient::addString("],\n", data); |
| 158 addProperty("visibility", String(style->visibility() == HIDDEN ? "hidden" :
"visible"), data); |
| 159 addProperty("display", String(style->display() == NONE ? "none" : "block"),
data); |
| 160 addProperty("direction", String(style->direction() == RTL ? "rtl" : "ltr"),
data); |
| 161 addProperty("unicodeBidi", String(isOverride(style->unicodeBidi()) ? "bidi-o
verride" : "normal"), data); |
| 162 PagePopupClient::addString("},\n", data); |
| 163 } |
| 164 |
| 165 void PopupMenuImpl::addOption(HTMLOptionElement& element, SharedBuffer* data) |
| 166 { |
| 167 PagePopupClient::addString("{\n", data); |
| 168 PagePopupClient::addString("type: \"option\",\n", data); |
| 169 addProperty("label", element.text(), data); |
| 170 addProperty("title", element.title(), data); |
| 171 addProperty("value", element.listIndex(), data); |
| 172 addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr)
, data); |
| 173 addProperty("disabled", element.isDisabledFormControl(), data); |
| 174 addElementStyle(element, data); |
| 175 PagePopupClient::addString("},\n", data); |
| 176 } |
| 177 |
| 178 void PopupMenuImpl::addOptGroup(HTMLOptGroupElement& element, SharedBuffer* data
) |
| 179 { |
| 180 PagePopupClient::addString("{\n", data); |
| 181 PagePopupClient::addString("type: \"optgroup\",\n", data); |
| 182 addProperty("label", element.groupLabelText(), data); |
| 183 addProperty("title", element.title(), data); |
| 184 addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr)
, data); |
| 185 addProperty("disabled", element.isDisabledFormControl(), data); |
| 186 addElementStyle(element, data); |
| 187 PagePopupClient::addString("children: [", data); |
| 188 for (HTMLElement& child : Traversal<HTMLElement>::childrenOf(element)) { |
| 189 if (isHTMLOptionElement(child)) |
| 190 addOption(toHTMLOptionElement(child), data); |
| 191 if (isHTMLOptGroupElement(child)) |
| 192 addOptGroup(toHTMLOptGroupElement(child), data); |
| 193 if (isHTMLHRElement(child)) |
| 194 addSeparator(toHTMLHRElement(child), data); |
| 195 } |
| 196 PagePopupClient::addString("],\n", data); |
| 197 PagePopupClient::addString("},\n", data); |
| 198 } |
| 199 |
| 200 void PopupMenuImpl::addSeparator(HTMLHRElement& element, SharedBuffer* data) |
| 201 { |
| 202 PagePopupClient::addString("{\n", data); |
| 203 PagePopupClient::addString("type: \"separator\",\n", data); |
| 204 addProperty("title", element.title(), data); |
| 205 addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr)
, data); |
| 206 addProperty("disabled", element.isDisabledFormControl(), data); |
| 207 addElementStyle(element, data); |
| 208 PagePopupClient::addString("},\n", data); |
| 209 } |
| 210 |
| 211 void PopupMenuImpl::didWriteDocument(Document* document) |
| 212 { |
| 213 Document& ownerDocument = ownerElement().document(); |
| 214 document->styleEngine()->setFontSelector(PopupMenuCSSFontSelector::create(do
cument, ownerDocument.styleEngine()->fontSelector())); |
| 215 } |
| 216 |
| 217 void PopupMenuImpl::setValueAndClosePopup(int numValue, const String& stringValu
e) |
| 218 { |
| 219 ASSERT(m_popup); |
| 220 ASSERT(m_client); |
| 221 bool success; |
| 222 int listIndex = stringValue.toInt(&success); |
| 223 ASSERT(success); |
| 224 m_client->selectionChanged(listIndex); |
| 225 m_client->valueChanged(listIndex); |
| 226 closePopup(); |
| 227 } |
| 228 |
| 229 void PopupMenuImpl::setValue(const String& value) |
| 230 { |
| 231 ASSERT(m_client); |
| 232 bool success; |
| 233 int listIndex = value.toInt(&success); |
| 234 ASSERT(success); |
| 235 m_client->setTextFromItem(listIndex); |
| 236 // FIXME: Wrong menu list text when switching from keyboard to mouse. We nee
d something like PopupListBox::m_originalIndex. |
| 237 } |
| 238 |
| 239 void PopupMenuImpl::didClosePopup() |
| 240 { |
| 241 m_popup = 0; |
| 242 m_client->popupDidHide(); |
| 243 } |
| 244 |
| 245 Element& PopupMenuImpl::ownerElement() |
| 246 { |
| 247 return m_client->ownerElement(); |
| 248 } |
| 249 |
| 250 void PopupMenuImpl::closePopup() |
| 251 { |
| 252 if (m_popup) |
| 253 m_chromeClient->closePagePopup(m_popup); |
| 254 } |
| 255 |
| 256 void PopupMenuImpl::trace(Visitor* visitor) |
| 257 { |
| 258 PopupMenu::trace(visitor); |
| 259 } |
| 260 |
| 261 void PopupMenuImpl::dispose() |
| 262 { |
| 263 closePopup(); |
| 264 } |
| 265 |
| 266 void PopupMenuImpl::show(const FloatQuad& /*controlPosition*/, const IntSize& /*
controlSize*/, int /*index*/) |
| 267 { |
| 268 ASSERT(!m_popup); |
| 269 m_popup = m_chromeClient->openPagePopup(this, m_client->elementRectRelativeT
oRootView()); |
| 270 } |
| 271 |
| 272 void PopupMenuImpl::hide() |
| 273 { |
| 274 if (m_popup) |
| 275 m_chromeClient->closePagePopup(m_popup); |
| 276 } |
| 277 |
| 278 void PopupMenuImpl::updateFromElement() |
| 279 { |
| 280 RefPtr<SharedBuffer> data = SharedBuffer::create(); |
| 281 PagePopupClient::addString("window.updateData = {\n", data.get()); |
| 282 PagePopupClient::addString("type: \"update\",\n", data.get()); |
| 283 PagePopupClient::addString("children: [", data.get()); |
| 284 for (HTMLElement& child : Traversal<HTMLElement>::childrenOf(ownerElement())
) { |
| 285 if (isHTMLOptionElement(child)) |
| 286 addOption(toHTMLOptionElement(child), data.get()); |
| 287 if (isHTMLOptGroupElement(child)) |
| 288 addOptGroup(toHTMLOptGroupElement(child), data.get()); |
| 289 if (isHTMLHRElement(child)) |
| 290 addSeparator(toHTMLHRElement(child), data.get()); |
| 291 } |
| 292 PagePopupClient::addString("],\n", data.get()); |
| 293 PagePopupClient::addString("}\n", data.get()); |
| 294 m_popup->postMessage(String(data->data(), data->size())); |
| 295 } |
| 296 |
| 297 |
| 298 void PopupMenuImpl::disconnectClient() |
| 299 { |
| 300 m_client = 0; |
| 301 #if ENABLE(OILPAN) |
| 302 // Cannot be done during finalization, so instead done when the |
| 303 // render object is destroyed and disconnected. |
| 304 // |
| 305 // FIXME: do this always, regardless of ENABLE(OILPAN). |
| 306 dispose(); |
| 307 #endif |
| 308 } |
| 309 |
| 310 } // namespace blink |
OLD | NEW |