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 "core/html/HTMLDialogElement.h" 28 29 #include "bindings/v8/ExceptionState.h" 30 #include "core/dom/ExceptionCode.h" 31 #include "core/page/FrameView.h" 32 #include "core/rendering/RenderBlock.h" 33 #include "core/rendering/style/RenderStyle.h" 34 35 namespace WebCore { 36 37 using namespace HTMLNames; 38 39 static bool needsCenteredPositioning(const RenderStyle* style) 40 { 41 return style->position() == AbsolutePosition && style->hasAutoTopAndBottom(); 42 } 43 44 HTMLDialogElement::HTMLDialogElement(const QualifiedName& tagName, Document* document) 45 : HTMLElement(tagName, document) 46 , m_topIsValid(false) 47 , m_top(0) 48 , m_returnValue("") 49 { 50 ASSERT(hasTagName(dialogTag)); 51 setHasCustomStyleCallbacks(); 52 ScriptWrappable::init(this); 53 } 54 55 PassRefPtr<HTMLDialogElement> HTMLDialogElement::create(const QualifiedName& tagName, Document* document) 56 { 57 return adoptRef(new HTMLDialogElement(tagName, document)); 58 } 59 60 void HTMLDialogElement::close(const String& returnValue, ExceptionState& es) 61 { 62 if (!fastHasAttribute(openAttr)) { 63 es.throwDOMException(InvalidStateError); 64 return; 65 } 66 setBooleanAttribute(openAttr, false); 67 document()->removeFromTopLayer(this); 68 m_topIsValid = false; 69 70 if (!returnValue.isNull()) 71 m_returnValue = returnValue; 72 } 73 74 PassRefPtr<RenderStyle> HTMLDialogElement::customStyleForRenderer() 75 { 76 RefPtr<RenderStyle> originalStyle = originalStyleForRenderer(); 77 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); 78 79 // Override top to remain centered after style recalcs. 80 if (needsCenteredPositioning(style.get()) && m_topIsValid) 81 style->setTop(Length(m_top.toInt(), WebCore::Fixed)); 82 83 return style.release(); 84 } 85 86 void HTMLDialogElement::reposition() 87 { 88 // Layout because we need to know our ancestors' positions and our own height. 89 document()->updateLayoutIgnorePendingStylesheets(); 90 91 RenderBox* box = renderBox(); 92 if (!box || !needsCenteredPositioning(box->style())) 93 return; 94 95 // Set up dialog's position to be safe-centered in the viewport. 96 // FIXME: Figure out what to do in vertical writing mode. 97 FrameView* frameView = document()->view(); 98 int scrollTop = frameView->scrollOffset().height(); 99 int visibleHeight = frameView->visibleContentRect(ScrollableArea::IncludeScrollbars).height(); 100 m_top = scrollTop; 101 if (box->height() < visibleHeight) 102 m_top += (visibleHeight - box->height()) / 2; 103 m_topIsValid = true; 104 105 setNeedsStyleRecalc(LocalStyleChange); 106 } 107 108 void HTMLDialogElement::show() 109 { 110 if (fastHasAttribute(openAttr)) 111 return; 112 setBooleanAttribute(openAttr, true); 113 reposition(); 114 } 115 116 void HTMLDialogElement::showModal(ExceptionState& es) 117 { 118 if (fastHasAttribute(openAttr) || !inDocument()) { 119 es.throwDOMException(InvalidStateError); 120 return; 121 } 122 document()->addToTopLayer(this); 123 setBooleanAttribute(openAttr, true); 124 reposition(); 125 } 126 127 bool HTMLDialogElement::isPresentationAttribute(const QualifiedName& name) const 128 { 129 // FIXME: Workaround for <https://bugs.webkit.org/show_bug.cgi?id=91058>: modifying an attribute for which there is an attribute selector 130 // in html.css sometimes does not trigger a style recalc. 131 if (name == openAttr) 132 return true; 133 134 return HTMLElement::isPresentationAttribute(name); 135 } 136 137 bool HTMLDialogElement::shouldBeReparentedUnderRenderView(const RenderStyle* style) const 138 { 139 if (style && style->position() == AbsolutePosition) 140 return true; 141 return Element::shouldBeReparentedUnderRenderView(style); 142 } 143 144 } // namespace WebCore 145