Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2010 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/ColorInputType.h"
     33 
     34 #include "CSSPropertyNames.h"
     35 #include "RuntimeEnabledFeatures.h"
     36 #include "bindings/v8/ExceptionStatePlaceholder.h"
     37 #include "bindings/v8/ScriptController.h"
     38 #include "core/dom/MouseEvent.h"
     39 #include "core/dom/shadow/ShadowRoot.h"
     40 #include "core/html/HTMLDataListElement.h"
     41 #include "core/html/HTMLDivElement.h"
     42 #include "core/html/HTMLInputElement.h"
     43 #include "core/html/HTMLOptionElement.h"
     44 #include "core/html/InputTypeNames.h"
     45 #include "core/page/Chrome.h"
     46 #include "core/platform/graphics/Color.h"
     47 #include "core/rendering/RenderView.h"
     48 #include "wtf/PassOwnPtr.h"
     49 #include "wtf/text/WTFString.h"
     50 
     51 namespace WebCore {
     52 
     53 using namespace HTMLNames;
     54 
     55 static bool isValidColorString(const String& value)
     56 {
     57     if (value.isEmpty())
     58         return false;
     59     if (value[0] != '#')
     60         return false;
     61 
     62     // We don't accept #rgb and #aarrggbb formats.
     63     if (value.length() != 7)
     64         return false;
     65     StyleColor color(value);
     66     return color.isValid() && !color.hasAlpha();
     67 }
     68 
     69 PassOwnPtr<InputType> ColorInputType::create(HTMLInputElement* element)
     70 {
     71     return adoptPtr(new ColorInputType(element));
     72 }
     73 
     74 ColorInputType::~ColorInputType()
     75 {
     76     endColorChooser();
     77 }
     78 
     79 void ColorInputType::attach()
     80 {
     81     observeFeatureIfVisible(UseCounter::InputTypeColor);
     82 }
     83 
     84 bool ColorInputType::isColorControl() const
     85 {
     86     return true;
     87 }
     88 
     89 const AtomicString& ColorInputType::formControlType() const
     90 {
     91     return InputTypeNames::color();
     92 }
     93 
     94 bool ColorInputType::supportsRequired() const
     95 {
     96     return false;
     97 }
     98 
     99 String ColorInputType::fallbackValue() const
    100 {
    101     return String("#000000");
    102 }
    103 
    104 String ColorInputType::sanitizeValue(const String& proposedValue) const
    105 {
    106     if (!isValidColorString(proposedValue))
    107         return fallbackValue();
    108 
    109     return proposedValue.lower();
    110 }
    111 
    112 StyleColor ColorInputType::valueAsColor() const
    113 {
    114     return StyleColor(element()->value());
    115 }
    116 
    117 void ColorInputType::createShadowSubtree()
    118 {
    119     ASSERT(element()->shadow());
    120 
    121     Document* document = element()->document();
    122     RefPtr<HTMLDivElement> wrapperElement = HTMLDivElement::create(document);
    123     wrapperElement->setPart(AtomicString("-webkit-color-swatch-wrapper", AtomicString::ConstructFromLiteral));
    124     RefPtr<HTMLDivElement> colorSwatch = HTMLDivElement::create(document);
    125     colorSwatch->setPart(AtomicString("-webkit-color-swatch", AtomicString::ConstructFromLiteral));
    126     wrapperElement->appendChild(colorSwatch.release(), ASSERT_NO_EXCEPTION);
    127     element()->userAgentShadowRoot()->appendChild(wrapperElement.release(), ASSERT_NO_EXCEPTION);
    128 
    129     updateColorSwatch();
    130 }
    131 
    132 void ColorInputType::setValue(const String& value, bool valueChanged, TextFieldEventBehavior eventBehavior)
    133 {
    134     InputType::setValue(value, valueChanged, eventBehavior);
    135 
    136     if (!valueChanged)
    137         return;
    138 
    139     updateColorSwatch();
    140     if (m_chooser)
    141         m_chooser->setSelectedColor(valueAsColor().color());
    142 }
    143 
    144 void ColorInputType::handleDOMActivateEvent(Event* event)
    145 {
    146     if (element()->isDisabledFormControl() || !element()->renderer())
    147         return;
    148 
    149     if (!ScriptController::processingUserGesture())
    150         return;
    151 
    152     Chrome* chrome = this->chrome();
    153     if (chrome && !m_chooser)
    154         m_chooser = chrome->createColorChooser(this, valueAsColor().color());
    155 
    156     event->setDefaultHandled();
    157 }
    158 
    159 void ColorInputType::detach()
    160 {
    161     endColorChooser();
    162 }
    163 
    164 bool ColorInputType::shouldRespectListAttribute()
    165 {
    166     return InputType::themeSupportsDataListUI(this);
    167 }
    168 
    169 bool ColorInputType::typeMismatchFor(const String& value) const
    170 {
    171     return !isValidColorString(value);
    172 }
    173 
    174 void ColorInputType::didChooseColor(const Color& color)
    175 {
    176     if (element()->isDisabledFormControl() || color == valueAsColor())
    177         return;
    178     element()->setValueFromRenderer(color.serialized());
    179     updateColorSwatch();
    180     element()->dispatchFormControlChangeEvent();
    181 }
    182 
    183 void ColorInputType::didEndChooser()
    184 {
    185     m_chooser.clear();
    186 }
    187 
    188 void ColorInputType::endColorChooser()
    189 {
    190     if (m_chooser)
    191         m_chooser->endChooser();
    192 }
    193 
    194 void ColorInputType::updateColorSwatch()
    195 {
    196     HTMLElement* colorSwatch = shadowColorSwatch();
    197     if (!colorSwatch)
    198         return;
    199 
    200     colorSwatch->setInlineStyleProperty(CSSPropertyBackgroundColor, element()->value());
    201 }
    202 
    203 HTMLElement* ColorInputType::shadowColorSwatch() const
    204 {
    205     ShadowRoot* shadow = element()->userAgentShadowRoot();
    206     return shadow ? toHTMLElement(shadow->firstChild()->firstChild()) : 0;
    207 }
    208 
    209 IntRect ColorInputType::elementRectRelativeToRootView() const
    210 {
    211     return element()->document()->view()->contentsToRootView(element()->pixelSnappedBoundingBox());
    212 }
    213 
    214 Color ColorInputType::currentColor()
    215 {
    216     return valueAsColor().color();
    217 }
    218 
    219 bool ColorInputType::shouldShowSuggestions() const
    220 {
    221     if (RuntimeEnabledFeatures::dataListElementEnabled())
    222         return element()->fastHasAttribute(listAttr);
    223 
    224     return false;
    225 }
    226 
    227 Vector<Color> ColorInputType::suggestions() const
    228 {
    229     Vector<Color> suggestions;
    230     if (RuntimeEnabledFeatures::dataListElementEnabled()) {
    231         HTMLDataListElement* dataList = element()->dataList();
    232         if (dataList) {
    233             RefPtr<HTMLCollection> options = dataList->options();
    234             for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); i++) {
    235                 if (!element()->isValidValue(option->value()))
    236                     continue;
    237                 StyleColor color(option->value());
    238                 if (!color.isValid())
    239                     continue;
    240                 suggestions.append(color.color());
    241             }
    242         }
    243     }
    244     return suggestions;
    245 }
    246 
    247 } // namespace WebCore
    248