Home | History | Annotate | Download | only in shadow
      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 
     49 namespace WebCore {
     50 
     51 using namespace HTMLNames;
     52 
     53 // FIXME: This class is only used in Chromium and has no layout tests.
     54 
     55 PasswordGeneratorButtonElement::PasswordGeneratorButtonElement(Document* document)
     56     : HTMLDivElement(HTMLNames::divTag, document)
     57     , m_isInHoverState(false)
     58 {
     59     setHasCustomStyleCallbacks();
     60 }
     61 
     62 static 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 
     84 void 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 
    103 inline 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 
    110 void 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 
    120 PassRefPtr<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 
    132 RenderObject* PasswordGeneratorButtonElement::createRenderer(RenderStyle*)
    133 {
    134     RenderImage* image = new RenderImage(this);
    135     image->setImageResource(RenderImageResource::create());
    136     return image;
    137 }
    138 
    139 void PasswordGeneratorButtonElement::attach(const AttachContext& context)
    140 {
    141     HTMLDivElement::attach(context);
    142     updateImage();
    143 }
    144 
    145 ImageResource* 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 
    154 ImageResource* 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 
    163 void 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 
    193 bool PasswordGeneratorButtonElement::willRespondToMouseMoveEvents()
    194 {
    195     const HTMLInputElement* input = hostInput();
    196     if (!input->isDisabledOrReadOnly())
    197         return true;
    198 
    199     return HTMLDivElement::willRespondToMouseMoveEvents();
    200 }
    201 
    202 bool 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