WebCore/ChangeLog

 12010-11-04 Kent Tamura <tkent@chromium.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 Implement form validation message UI
 6 https://bugs.webkit.org/show_bug.cgi?id=48980
 7
 8 * Add four internal pseudo selectors:
 9 - -webkit-validation-bubble
 10 - -webkit-validation-bubble-message
 11 - -webkit-validation-bubble-top-outer-arrow
 12 - -webkit-validation-bubble-top-inner-arrow
 13 * Add ShadowSimpleElement
 14 This is similar to ShadowBlockElement except ShadowSimpleElement is not
 15 a block element.
 16 * Implement ValidationMessage functions
 17 Show the message for <the number of characters> / 20.0 seconds.
 18
 19 No new tests because the new behavior is strongly timing-dependent.
 20
 21 * css/CSSSelector.cpp:
 22 (WebCore::CSSSelector::pseudoId):
 23 (WebCore::nameToPseudoTypeMap):
 24 (WebCore::CSSSelector::extractPseudoType):
 25 * css/CSSSelector.h:
 26 * css/html.css:
 27 (::-webkit-validation-bubble):
 28 (::-webkit-validation-bubble-message):
 29 (::-webkit-validation-bubble-top-outer-arrow):
 30 (::-webkit-validation-bubble-top-inner-arrow):
 31 * html/ValidationMessage.cpp:
 32 (WebCore::ValidationMessage::ValidationMessage):
 33 (WebCore::ValidationMessage::setMessage):
 34 (WebCore::ValidationMessage::setMessageDOMAndStartTimer):
 35 (WebCore::ValidationMessage::buildBubbleTree):
 36 (WebCore::ValidationMessage::hideMessage):
 37 * html/ValidationMessage.h:
 38 * rendering/ShadowElement.cpp:
 39 (WebCore::ShadowSimpleElement::ShadowSimpleElement):
 40 (WebCore::ShadowSimpleElement::create):
 41 (WebCore::ShadowSimpleElement::createForPart):
 42 (WebCore::ShadowSimpleElement::initializeForPart):
 43 (WebCore::ShadowSimpleElement::createStyleForPart):
 44 (WebCore::ShadowBlockElement::ShadowBlockElement):
 45 (WebCore::ShadowBlockElement::updateStyleForPart):
 46 (WebCore::ShadowBlockElement::createForPart):
 47 (WebCore::ShadowBlockElement::createStyleForPart):
 48 * rendering/ShadowElement.h:
 49 (WebCore::ShadowElement::shadowParentNode):
 50 * rendering/style/RenderStyleConstants.h:
 51
1522010-11-03 Kent Tamura <tkent@chromium.org>
253
354 Reviewed by Dimitri Glazkov.

WebCore/css/CSSSelector.cpp

@@PseudoId CSSSelector::pseudoId(PseudoType type)
254254 case PseudoFullScreenDocument:
255255 return FULL_SCREEN_DOCUMENT;
256256#endif
 257
 258 case PseudoValidationBubble:
 259 return VALIDATION_BUBBLE;
 260 case PseudoValidationBubbleMessage:
 261 return VALIDATION_BUBBLE_MESSAGE;
 262 case PseudoValidationBubbleTopInner:
 263 return VALIDATION_BUBBLE_TOP_INNER;
 264 case PseudoValidationBubbleTopOuter:
 265 return VALIDATION_BUBBLE_TOP_OUTER;
257266
258267 case PseudoInputListButton:
259268#if ENABLE(DATALIST)

@@static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap(
417426 DEFINE_STATIC_LOCAL(AtomicString, selection, ("selection"));
418427 DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-thumb"));
419428 DEFINE_STATIC_LOCAL(AtomicString, target, ("target"));
 429 DEFINE_STATIC_LOCAL(AtomicString, validationBubble, ("-webkit-validation-bubble"));
 430 DEFINE_STATIC_LOCAL(AtomicString, validationBubbleMessage, ("-webkit-validation-bubble-message"));
 431 DEFINE_STATIC_LOCAL(AtomicString, validationBubbleTopInner, ("-webkit-validation-bubble-top-inner-arrow"));
 432 DEFINE_STATIC_LOCAL(AtomicString, validationBubbleTopOuter, ("-webkit-validation-bubble-top-outer-arrow"));
420433 DEFINE_STATIC_LOCAL(AtomicString, visited, ("visited"));
421434 DEFINE_STATIC_LOCAL(AtomicString, windowInactive, ("window-inactive"));
422435 DEFINE_STATIC_LOCAL(AtomicString, decrement, ("decrement"));

@@static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap(
544557 nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection);
545558 nameToPseudoType->set(sliderThumb.impl(), CSSSelector::PseudoSliderThumb);
546559 nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget);
 560 nameToPseudoType->set(validationBubble.impl(), CSSSelector::PseudoValidationBubble);
 561 nameToPseudoType->set(validationBubbleMessage.impl(), CSSSelector::PseudoValidationBubbleMessage);
 562 nameToPseudoType->set(validationBubbleTopInner.impl(), CSSSelector::PseudoValidationBubbleTopInner);
 563 nameToPseudoType->set(validationBubbleTopOuter.impl(), CSSSelector::PseudoValidationBubbleTopOuter);
547564 nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited);
548565 nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage);
549566 nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage);

@@void CSSSelector::extractPseudoType() const
629646 case PseudoSearchResultsButton:
630647 case PseudoSelection:
631648 case PseudoSliderThumb:
 649 case PseudoValidationBubble:
 650 case PseudoValidationBubbleMessage:
 651 case PseudoValidationBubbleTopInner:
 652 case PseudoValidationBubbleTopOuter:
632653 element = true;
633654 break;
634655 case PseudoUnknown:

WebCore/css/CSSSelector.h

@@namespace WebCore {
221221 PseudoFullScreen,
222222 PseudoFullScreenDocument,
223223#endif
 224 PseudoValidationBubble,
 225 PseudoValidationBubbleMessage,
 226 PseudoValidationBubbleTopInner,
 227 PseudoValidationBubbleTopOuter,
224228 };
225229
226230 enum MarginBoxType {

WebCore/css/html.css

@@option {
530530 font-weight: normal;
531531}
532532
 533/* form validation message bubble */
 534
 535::-webkit-validation-bubble {
 536 display: block;
 537 z-index: 10000; /* signed int */
 538 position: absolute;
 539 opacity: 1;
 540 line-height: 0px;
 541 -webkit-transition: opacity 0.5s ease;
 542}
 543
 544::-webkit-validation-bubble-message {
 545 display: block;
 546 font: message-box;
 547 min-width: 50px;
 548 max-width: 200px;
 549 border: solid 2px black;
 550 background: -webkit-gradient(linear, left top, left bottom, from(#f9f9fb), to(#e4e4f0));
 551 padding: 8px;
 552 -webkit-border-radius: 8px;
 553 -webkit-box-shadow: 4px 4px 4px rgba(204,204,204,0.7);
 554}
 555
 556::-webkit-validation-bubble-top-outer-arrow {
 557 display: inline-block;
 558 position: relative;
 559 left: 14px;
 560 height: 0;
 561 width: 0;
 562 border-style: solid;
 563 border-width: 14px;
 564 border-bottom-color: black;
 565 border-right-color: transparent;
 566 border-top-width: 0;
 567 border-left-width: 0;
 568}
 569
 570::-webkit-validation-bubble-top-inner-arrow {
 571 display: inline-block;
 572 height: 0;
 573 width: 0;
 574 border-style: solid;
 575 border-width: 10px; /* <outer whole width> - <message border width> * 2 */
 576 border-bottom-color: #f9f9fb;
 577 border-right-color: transparent;
 578 border-top-width: 0;
 579 border-left-width: 0;
 580 position: relative;
 581 top: 2px; /* <message border width> */
 582 left: 2px; /* <outer position> + <message border width> - <outer whole width> */
 583}
 584
533585/* meter */
534586
535587meter {

WebCore/html/ValidationMessage.cpp

3131#include "config.h"
3232#include "ValidationMessage.h"
3333
 34#include "HTMLBRElement.h"
 35#include "HTMLNames.h"
 36#include "RenderObject.h"
 37#include "ShadowElement.h"
 38#include "Text.h"
3439#include <wtf/PassOwnPtr.h>
3540
3641namespace WebCore {
3742
 43using namespace HTMLNames;
 44
3845ALWAYS_INLINE ValidationMessage::ValidationMessage(HTMLFormControlElement* element)
3946 : m_element(element)
4047{

@@PassOwnPtr<ValidationMessage> ValidationMessage::create(HTMLFormControlElement*
5259
5360void ValidationMessage::setMessage(const String& message)
5461{
55  // FIXME: Construct validation message UI if m_message is empty.
56 
5762 m_message = message;
 63 if (!m_bubble) {
 64 // We don't build a shadow tree here because it makes m_element
 65 // needsLayout() state and m_element->isFocusable() in
 66 // HTMLFormElement::validateInteractively() can't be called.
 67 m_timer.set(new Timer<ValidationMessage>(this, &ValidationMessage::buildBubbleTree));
 68 m_timer->startOneShot(0);
 69 } else {
 70 setMessageDOMAndStartTimer();
 71 }
 72}
 73
 74void ValidationMessage::setMessageDOMAndStartTimer()
 75{
 76 m_bubbleMessage->removeAllChildren();
 77 Vector<String> lines;
 78 m_message.split('\n', lines);
 79 Document* doc = m_bubbleMessage->document();
 80 ExceptionCode ec = 0;
 81 for (unsigned i = 0; i < lines.size(); ++i) {
 82 if (i) {
 83 m_bubbleMessage->appendChild(HTMLBRElement::create(doc), ec);
 84 m_bubbleMessage->appendChild(Text::create(doc, lines[i]), ec);
 85 } else {
 86 RefPtr<HTMLElement> bold = HTMLElement::create(bTag, doc);
 87 bold->setInnerText(lines[i], ec);
 88 m_bubbleMessage->appendChild(bold.release(), ec);
 89 }
 90 }
5891
5992 m_timer.set(new Timer<ValidationMessage>(this, &ValidationMessage::hideMessage));
60  m_timer->startOneShot(6.0); // FIXME: should be <message length> * something.
 93 m_timer->startOneShot(max(5.0, m_message.length() / 20.0));
6194}
6295
63 void ValidationMessage::hideMessage(Timer<ValidationMessage>*)
 96void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*)
6497{
65  // FIXME: Implement.
 98 fprintf(stderr, "%s: Create a shadow tree\n", __func__);
 99 m_bubble = ShadowSimpleElement::createForPart(m_element, VALIDATION_BUBBLE);
 100 RenderObject* renderer = m_bubble->renderer();
 101
 102 m_bubbleTopOuter = ShadowSimpleElement::createForPart(m_bubble.get(), VALIDATION_BUBBLE_TOP_OUTER);
 103 renderer->addChild(m_bubbleTopOuter->renderer());
66104
 105 m_bubbleTopInner = ShadowSimpleElement::createForPart(m_bubble.get(), VALIDATION_BUBBLE_TOP_INNER);
 106 renderer->addChild(m_bubbleTopInner->renderer());
 107
 108 m_bubbleMessage = ShadowSimpleElement::createForPart(m_bubble.get(), VALIDATION_BUBBLE_MESSAGE);
 109 renderer->addChild(m_bubbleMessage->renderer());
 110 setMessageDOMAndStartTimer();
 111
 112 m_element->renderer()->addChild(renderer);
 113 renderer->style()->setOpacity(0.9f);
 114
 115 // FIXME: Use transition to show the bubble.
 116 // FIXME: Adjust the bubble location.
 117}
 118
 119void ValidationMessage::hideMessage(Timer<ValidationMessage>*)
 120{
 121 if (m_bubble) {
 122 m_bubbleTopOuter->detach();
 123 m_bubbleTopOuter = 0;
 124 m_bubbleTopInner->detach();
 125 m_bubbleTopInner = 0;
 126 m_bubbleMessage->detach();
 127 m_bubbleMessage = 0;
 128 m_bubble->detach();
 129 m_bubble = 0;
 130 }
67131 m_message = String();
68132}
69133

WebCore/html/ValidationMessage.h

3434#include "Timer.h"
3535#include <wtf/Noncopyable.h>
3636#include <wtf/OwnPtr.h>
 37#include <wtf/RefPtr.h>
3738#include <wtf/text/WTFString.h>
3839
3940namespace WebCore {
4041
 42class HTMLElement;
4143class HTMLFormControlElement;
4244
4345class ValidationMessage : public Noncopyable {

@@public:
4951
5052private:
5153 ValidationMessage(HTMLFormControlElement*);
 54 void setMessageDOMAndStartTimer();
 55 void buildBubbleTree(Timer<ValidationMessage>*);
5256 void hideMessage(Timer<ValidationMessage>* = 0);
5357
5458 HTMLFormControlElement* m_element;
5559 String m_message;
5660 OwnPtr<Timer<ValidationMessage> > m_timer;
 61 RefPtr<HTMLElement> m_bubble;
 62 RefPtr<HTMLElement> m_bubbleTopOuter;
 63 RefPtr<HTMLElement> m_bubbleTopInner;
 64 RefPtr<HTMLElement> m_bubbleMessage;
5765};
5866
5967} // namespace WebCore

WebCore/rendering/ShadowElement.cpp

@@namespace WebCore {
2929
3030using namespace HTMLNames;
3131
 32inline ShadowSimpleElement::ShadowSimpleElement(HTMLElement* shadowParent)
 33 : ShadowElement<HTMLDivElement>(divTag, shadowParent)
 34{
 35}
 36
 37PassRefPtr<ShadowSimpleElement> ShadowSimpleElement::create(HTMLElement* shadowParent)
 38{
 39 return adoptRef(new ShadowSimpleElement(shadowParent));
 40}
 41
 42PassRefPtr<ShadowSimpleElement> ShadowSimpleElement::createForPart(HTMLElement* shadowParent, PseudoId pseudoId)
 43{
 44 RefPtr<ShadowSimpleElement> part = create(shadowParent);
 45 part->initializeForPart(pseudoId);
 46 return part.release();
 47}
 48
 49void ShadowSimpleElement::initializeForPart(PseudoId pseudoId)
 50{
 51 RenderObject* parentRenderer = shadowParentNode()->renderer();
 52 RefPtr<RenderStyle> styleForPart = createStyleForPart(parentRenderer, pseudoId);
 53 setRenderer(createRenderer(parentRenderer->renderArena(), styleForPart.get()));
 54 renderer()->setAnimatableStyle(styleForPart.release());
 55 setAttached();
 56 setInDocument();
 57 return;
 58}
 59
 60PassRefPtr<RenderStyle> ShadowSimpleElement::createStyleForPart(RenderObject* parentRenderer, PseudoId pseudoId)
 61{
 62 RefPtr<RenderStyle> styleForPart;
 63 RenderStyle* pseudoStyle = parentRenderer->getCachedPseudoStyle(pseudoId);
 64 if (pseudoStyle)
 65 styleForPart = RenderStyle::clone(pseudoStyle);
 66 else
 67 styleForPart = RenderStyle::create();
 68
 69 styleForPart->inheritFrom(parentRenderer->style());
 70 return styleForPart.release();
 71}
 72
3273PassRefPtr<ShadowBlockElement> ShadowBlockElement::create(HTMLElement* shadowParent)
3374{
3475 return adoptRef(new ShadowBlockElement(shadowParent));
3576}
3677
3778ShadowBlockElement::ShadowBlockElement(HTMLElement* shadowParent)
38  : ShadowElement<HTMLDivElement>(divTag, shadowParent)
 79 : ShadowSimpleElement(shadowParent)
3980{
4081}
4182

@@void ShadowBlockElement::layoutAsPart(const IntRect& partRect)
63104void ShadowBlockElement::updateStyleForPart(PseudoId pseudoId)
64105{
65106 if (renderer()->style()->styleType() != pseudoId)
66  renderer()->setStyle(createStyleForPart(renderer()->parent(), pseudoId));
 107 renderer()->setAnimatableStyle(createStyleForPart(renderer()->parent(), pseudoId));
67108}
68109
69110PassRefPtr<ShadowBlockElement> ShadowBlockElement::createForPart(HTMLElement* shadowParent, PseudoId pseudoId)
70111{
71  RenderObject* parentRenderer = shadowParent->renderer();
72  RefPtr<RenderStyle> styleForPart = createStyleForPart(parentRenderer, pseudoId);
73112 RefPtr<ShadowBlockElement> part = create(shadowParent);
74  part->setRenderer(part->createRenderer(parentRenderer->renderArena(), styleForPart.get()));
75  part->renderer()->setStyle(styleForPart.release());
76  part->setAttached();
77  part->setInDocument();
 113 part->initializeForPart(pseudoId);
78114 return part.release();
79115}
80116
81117PassRefPtr<RenderStyle> ShadowBlockElement::createStyleForPart(RenderObject* parentRenderer, PseudoId pseudoId)
82118{
83  RefPtr<RenderStyle> styleForPart;
84  RenderStyle* pseudoStyle = parentRenderer->getCachedPseudoStyle(pseudoId);
85  if (pseudoStyle)
86  styleForPart = RenderStyle::clone(pseudoStyle);
87  else
88  styleForPart = RenderStyle::create();
89 
90  styleForPart->inheritFrom(parentRenderer->style());
 119 PassRefPtr<RenderStyle> styleForPart = ShadowSimpleElement::createStyleForPart(parentRenderer, pseudoId);
91120 styleForPart->setDisplay(BLOCK);
92121 styleForPart->setAppearance(NoControlPart);
93  return styleForPart.release();
 122 return styleForPart;
94123}
95124
96125bool ShadowBlockElement::partShouldHaveStyle(const RenderObject* parentRenderer, PseudoId pseudoId)

WebCore/rendering/ShadowElement.h

@@protected:
4444 }
4545
4646 HTMLElement* shadowParent() const { return m_shadowParent; }
 47 virtual ContainerNode* shadowParentNode() { return m_shadowParent; }
4748
4849private:
4950 virtual bool isShadowNode() const { return true; }
50  virtual ContainerNode* shadowParentNode() { return m_shadowParent; }
5151
5252 HTMLElement* m_shadowParent;
5353};
5454
55 class ShadowBlockElement : public ShadowElement<HTMLDivElement> {
 55class ShadowSimpleElement : public ShadowElement<HTMLDivElement> {
 56public:
 57 static PassRefPtr<ShadowSimpleElement> create(HTMLElement*);
 58 static PassRefPtr<ShadowSimpleElement> createForPart(HTMLElement*, PseudoId);
 59
 60protected:
 61 ShadowSimpleElement(HTMLElement*);
 62 void initializeForPart(PseudoId);
 63 virtual PassRefPtr<RenderStyle> createStyleForPart(RenderObject*, PseudoId);
 64};
 65
 66// This element forces its style to be "display:block".
 67class ShadowBlockElement : public ShadowSimpleElement {
5668public:
5769 static PassRefPtr<ShadowBlockElement> create(HTMLElement*);
5870 static PassRefPtr<ShadowBlockElement> createForPart(HTMLElement*, PseudoId);
59  static bool partShouldHaveStyle(const RenderObject* parentRenderer, PseudoId pseudoId);
 71 static bool partShouldHaveStyle(const RenderObject* parentRenderer, PseudoId);
6072 void layoutAsPart(const IntRect& partRect);
6173 void updateStyleForPart(PseudoId);
6274

@@protected:
6476 ShadowBlockElement(HTMLElement*);
6577
6678private:
67  static PassRefPtr<RenderStyle> createStyleForPart(RenderObject*, PseudoId);
 79 virtual PassRefPtr<RenderStyle> createStyleForPart(RenderObject*, PseudoId);
6880};
6981
7082class ShadowInputElement : public ShadowElement<HTMLInputElement> {
7183public:
7284 static PassRefPtr<ShadowInputElement> create(HTMLElement*);
 85
7386protected:
7487 ShadowInputElement(HTMLElement*);
7588};

WebCore/rendering/style/RenderStyleConstants.h

@@enum PseudoId {
7878 INPUT_LIST_BUTTON, INPUT_SPEECH_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON, VISITED_LINK, PROGRESS_BAR_VALUE,
7979 METER_HORIZONTAL_BAR, METER_HORIZONTAL_OPTIMUM, METER_HORIZONTAL_SUBOPTIMAL, METER_HORIZONTAL_EVEN_LESS_GOOD,
8080 METER_VERTICAL_BAR, METER_VERTICAL_OPTIMUM, METER_VERTICAL_SUBOPTIMAL, METER_VERTICAL_EVEN_LESS_GOOD,
 81 VALIDATION_BUBBLE, VALIDATION_BUBBLE_MESSAGE, VALIDATION_BUBBLE_TOP_INNER, VALIDATION_BUBBLE_TOP_OUTER,
8182 AFTER_LAST_INTERNAL_PSEUDOID,
8283 FULL_SCREEN, FULL_SCREEN_DOCUMENT,
8384 FIRST_PUBLIC_PSEUDOID = FIRST_LINE,