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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 29 */ 30 31#include "config.h" 32#include "core/html/shadow/PasswordGeneratorButtonElement.h" 33 34#include "CSSPropertyNames.h" 35#include "CSSValueKeywords.h" 36#include "core/dom/Event.h" 37#include "core/dom/NodeRenderStyle.h" 38#include "core/dom/shadow/ElementShadow.h" 39#include "core/dom/shadow/ShadowRoot.h" 40#include "core/html/HTMLInputElement.h" 41#include "core/html/shadow/HTMLShadowElement.h" 42#include "core/loader/cache/ImageResource.h" 43#include "core/page/Chrome.h" 44#include "core/page/ChromeClient.h" 45#include "core/page/Page.h" 46#include "core/platform/graphics/Image.h" 47#include "core/rendering/RenderImage.h" 48 49namespace WebCore { 50 51using namespace HTMLNames; 52 53// FIXME: This class is only used in Chromium and has no layout tests. 54 55PasswordGeneratorButtonElement::PasswordGeneratorButtonElement(Document* document) 56 : HTMLDivElement(HTMLNames::divTag, document) 57 , m_isInHoverState(false) 58{ 59 setHasCustomStyleCallbacks(); 60} 61 62static void getDecorationRootAndDecoratedRoot(HTMLInputElement* input, ShadowRoot*& decorationRoot, ShadowRoot*& decoratedRoot) 63{ 64 ShadowRoot* existingRoot = input->youngestShadowRoot(); 65 ShadowRoot* newRoot = 0; 66 while (existingRoot->childNodeCount() == 1 && existingRoot->firstChild()->hasTagName(shadowTag)) { 67 newRoot = existingRoot; 68 existingRoot = existingRoot->olderShadowRoot(); 69 ASSERT(existingRoot); 70 } 71 if (newRoot) { 72 newRoot->removeChild(newRoot->firstChild()); 73 } else { 74 // FIXME: This interacts really badly with author shadow roots because now 75 // we can interleave user agent and author shadow roots on the element meaning 76 // input.shadowRoot may be inaccessible if the browser has decided to decorate 77 // the input. 78 newRoot = input->ensureShadow()->addShadowRoot(input, ShadowRoot::UserAgentShadowRoot); 79 } 80 decorationRoot = newRoot; 81 decoratedRoot = existingRoot; 82} 83 84void PasswordGeneratorButtonElement::decorate(HTMLInputElement* input) 85{ 86 ASSERT(input); 87 ShadowRoot* existingRoot; 88 ShadowRoot* decorationRoot; 89 getDecorationRootAndDecoratedRoot(input, decorationRoot, existingRoot); 90 ASSERT(decorationRoot); 91 ASSERT(existingRoot); 92 RefPtr<HTMLDivElement> box = HTMLDivElement::create(input->document()); 93 decorationRoot->appendChild(box); 94 box->setInlineStyleProperty(CSSPropertyDisplay, CSSValueFlex); 95 box->setInlineStyleProperty(CSSPropertyAlignItems, CSSValueCenter); 96 ASSERT(existingRoot->childNodeCount() == 1); 97 toHTMLElement(existingRoot->firstChild())->setInlineStyleProperty(CSSPropertyFlexGrow, 1.0, CSSPrimitiveValue::CSS_NUMBER); 98 box->appendChild(HTMLShadowElement::create(HTMLNames::shadowTag, input->document())); 99 setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone); 100 box->appendChild(this); 101} 102 103inline HTMLInputElement* PasswordGeneratorButtonElement::hostInput() 104{ 105 // PasswordGeneratorButtonElement is created only by C++ code, and it is always 106 // in <input> shadow. 107 return toHTMLInputElement(shadowHost()); 108} 109 110void PasswordGeneratorButtonElement::updateImage() 111{ 112 if (!renderer() || !renderer()->isImage()) 113 return; 114 RenderImageResource* resource = toRenderImage(renderer())->imageResource(); 115 ImageResource* image = m_isInHoverState ? imageForHoverState() : imageForNormalState(); 116 ASSERT(image); 117 resource->setImageResource(image); 118} 119 120PassRefPtr<RenderStyle> PasswordGeneratorButtonElement::customStyleForRenderer() 121{ 122 RefPtr<RenderStyle> originalStyle = originalStyleForRenderer(); 123 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); 124 RenderStyle* inputStyle = hostInput()->renderStyle(); 125 ASSERT(inputStyle); 126 style->setWidth(Length(inputStyle->fontSize(), Fixed)); 127 style->setHeight(Length(inputStyle->fontSize(), Fixed)); 128 updateImage(); 129 return style.release(); 130} 131 132RenderObject* PasswordGeneratorButtonElement::createRenderer(RenderStyle*) 133{ 134 RenderImage* image = new RenderImage(this); 135 image->setImageResource(RenderImageResource::create()); 136 return image; 137} 138 139void PasswordGeneratorButtonElement::attach(const AttachContext& context) 140{ 141 HTMLDivElement::attach(context); 142 updateImage(); 143} 144 145ImageResource* PasswordGeneratorButtonElement::imageForNormalState() 146{ 147 if (!m_cachedImageForNormalState) { 148 RefPtr<Image> image = Image::loadPlatformResource("generatePassword"); 149 m_cachedImageForNormalState = new ImageResource(image.get()); 150 } 151 return m_cachedImageForNormalState.get(); 152} 153 154ImageResource* PasswordGeneratorButtonElement::imageForHoverState() 155{ 156 if (!m_cachedImageForHoverState) { 157 RefPtr<Image> image = Image::loadPlatformResource("generatePasswordHover"); 158 m_cachedImageForHoverState = new ImageResource(image.get()); 159 } 160 return m_cachedImageForHoverState.get(); 161} 162 163void PasswordGeneratorButtonElement::defaultEventHandler(Event* event) 164{ 165 RefPtr<HTMLInputElement> input = hostInput(); 166 if (!input || input->isDisabledOrReadOnly() || !event->isMouseEvent()) { 167 if (!event->defaultHandled()) 168 HTMLDivElement::defaultEventHandler(event); 169 return; 170 } 171 172 RefPtr<PasswordGeneratorButtonElement> protector(this); 173 if (event->type() == eventNames().clickEvent) { 174 if (ChromeClient* chromeClient = document()->page() ? document()->page()->chrome().client() : 0) 175 chromeClient->openPasswordGenerator(input.get()); 176 event->setDefaultHandled(); 177 } 178 179 if (event->type() == eventNames().mouseoverEvent) { 180 m_isInHoverState = true; 181 updateImage(); 182 } 183 184 if (event->type() == eventNames().mouseoutEvent) { 185 m_isInHoverState = false; 186 updateImage(); 187 } 188 189 if (!event->defaultHandled()) 190 HTMLDivElement::defaultEventHandler(event); 191} 192 193bool PasswordGeneratorButtonElement::willRespondToMouseMoveEvents() 194{ 195 const HTMLInputElement* input = hostInput(); 196 if (!input->isDisabledOrReadOnly()) 197 return true; 198 199 return HTMLDivElement::willRespondToMouseMoveEvents(); 200} 201 202bool PasswordGeneratorButtonElement::willRespondToMouseClickEvents() 203{ 204 const HTMLInputElement* input = hostInput(); 205 if (!input->isDisabledOrReadOnly()) 206 return true; 207 208 return HTMLDivElement::willRespondToMouseClickEvents(); 209} 210 211} // namespace WebCore 212