diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /WebCore/editing/DeleteButtonController.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'WebCore/editing/DeleteButtonController.cpp')
-rw-r--r-- | WebCore/editing/DeleteButtonController.cpp | 358 |
1 files changed, 0 insertions, 358 deletions
diff --git a/WebCore/editing/DeleteButtonController.cpp b/WebCore/editing/DeleteButtonController.cpp deleted file mode 100644 index 028edc8..0000000 --- a/WebCore/editing/DeleteButtonController.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DeleteButtonController.h" - -#include "CachedImage.h" -#include "CSSMutableStyleDeclaration.h" -#include "CSSPrimitiveValue.h" -#include "CSSPropertyNames.h" -#include "CSSValueKeywords.h" -#include "DeleteButton.h" -#include "Document.h" -#include "Editor.h" -#include "Frame.h" -#include "htmlediting.h" -#include "HTMLDivElement.h" -#include "HTMLNames.h" -#include "Image.h" -#include "Node.h" -#include "Range.h" -#include "RemoveNodeCommand.h" -#include "RenderBox.h" -#include "SelectionController.h" - -namespace WebCore { - -using namespace HTMLNames; - -const char* const DeleteButtonController::containerElementIdentifier = "WebKit-Editing-Delete-Container"; -const char* const DeleteButtonController::buttonElementIdentifier = "WebKit-Editing-Delete-Button"; -const char* const DeleteButtonController::outlineElementIdentifier = "WebKit-Editing-Delete-Outline"; - -DeleteButtonController::DeleteButtonController(Frame* frame) - : m_frame(frame) - , m_wasStaticPositioned(false) - , m_wasAutoZIndex(false) - , m_disableStack(0) -{ -} - -static bool isDeletableElement(const Node* node) -{ - if (!node || !node->isHTMLElement() || !node->inDocument() || !node->isContentEditable()) - return false; - - // In general we want to only draw the UI around object of a certain area, but we still keep the min width/height to - // make sure we don't end up with very thin or very short elements getting the UI. - const int minimumArea = 2500; - const int minimumWidth = 48; - const int minimumHeight = 16; - const unsigned minimumVisibleBorders = 1; - - RenderObject* renderer = node->renderer(); - if (!renderer || !renderer->isBox()) - return false; - - // Disallow the body element since it isn't practical to delete, and the deletion UI would be clipped. - if (node->hasTagName(bodyTag)) - return false; - - // Disallow elements with any overflow clip, since the deletion UI would be clipped as well. <rdar://problem/6840161> - if (renderer->hasOverflowClip()) - return false; - - // Disallow Mail blockquotes since the deletion UI would get in the way of editing for these. - if (isMailBlockquote(node)) - return false; - - RenderBox* box = toRenderBox(renderer); - IntRect borderBoundingBox = box->borderBoundingBox(); - if (borderBoundingBox.width() < minimumWidth || borderBoundingBox.height() < minimumHeight) - return false; - - if ((borderBoundingBox.width() * borderBoundingBox.height()) < minimumArea) - return false; - - if (renderer->isTable()) - return true; - - if (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(iframeTag)) - return true; - - if (renderer->isPositioned()) - return true; - - if (renderer->isRenderBlock() && !renderer->isTableCell()) { - RenderStyle* style = renderer->style(); - if (!style) - return false; - - // Allow blocks that have background images - if (style->hasBackgroundImage() && style->backgroundImage()->canRender(1.0f)) - return true; - - // Allow blocks with a minimum number of non-transparent borders - unsigned visibleBorders = style->borderTop().isVisible() + style->borderBottom().isVisible() + style->borderLeft().isVisible() + style->borderRight().isVisible(); - if (visibleBorders >= minimumVisibleBorders) - return true; - - // Allow blocks that have a different background from it's parent - ContainerNode* parentNode = node->parentNode(); - if (!parentNode) - return false; - - RenderObject* parentRenderer = parentNode->renderer(); - if (!parentRenderer) - return false; - - RenderStyle* parentStyle = parentRenderer->style(); - if (!parentStyle) - return false; - - if (renderer->hasBackground() && (!parentRenderer->hasBackground() || style->visitedDependentColor(CSSPropertyBackgroundColor) != parentStyle->visitedDependentColor(CSSPropertyBackgroundColor))) - return true; - } - - return false; -} - -static HTMLElement* enclosingDeletableElement(const VisibleSelection& selection) -{ - if (!selection.isContentEditable()) - return 0; - - RefPtr<Range> range = selection.toNormalizedRange(); - if (!range) - return 0; - - ExceptionCode ec = 0; - Node* container = range->commonAncestorContainer(ec); - ASSERT(container); - ASSERT(ec == 0); - - // The enclosingNodeOfType function only works on nodes that are editable - // (which is strange, given its name). - if (!container->isContentEditable()) - return 0; - - Node* element = enclosingNodeOfType(Position(container, 0), &isDeletableElement); - if (!element) - return 0; - - ASSERT(element->isHTMLElement()); - return static_cast<HTMLElement*>(element); -} - -void DeleteButtonController::respondToChangedSelection(const VisibleSelection& oldSelection) -{ - if (!enabled()) - return; - - HTMLElement* oldElement = enclosingDeletableElement(oldSelection); - HTMLElement* newElement = enclosingDeletableElement(m_frame->selection()->selection()); - if (oldElement == newElement) - return; - - // If the base is inside a deletable element, give the element a delete widget. - if (newElement) - show(newElement); - else - hide(); -} - -void DeleteButtonController::createDeletionUI() -{ - RefPtr<HTMLDivElement> container = HTMLDivElement::create(m_target->document()); - container->setIdAttribute(containerElementIdentifier); - - CSSMutableStyleDeclaration* style = container->getInlineStyleDecl(); - style->setProperty(CSSPropertyWebkitUserDrag, CSSValueNone); - style->setProperty(CSSPropertyWebkitUserSelect, CSSValueNone); - style->setProperty(CSSPropertyWebkitUserModify, CSSValueNone); - style->setProperty(CSSPropertyVisibility, CSSValueHidden); - style->setProperty(CSSPropertyPosition, CSSValueAbsolute); - style->setProperty(CSSPropertyCursor, CSSValueDefault); - style->setProperty(CSSPropertyTop, "0"); - style->setProperty(CSSPropertyRight, "0"); - style->setProperty(CSSPropertyBottom, "0"); - style->setProperty(CSSPropertyLeft, "0"); - - RefPtr<HTMLDivElement> outline = HTMLDivElement::create(m_target->document()); - outline->setIdAttribute(outlineElementIdentifier); - - const int borderWidth = 4; - const int borderRadius = 6; - - style = outline->getInlineStyleDecl(); - style->setProperty(CSSPropertyPosition, CSSValueAbsolute); - style->setProperty(CSSPropertyZIndex, String::number(-1000000)); - style->setProperty(CSSPropertyTop, String::number(-borderWidth - m_target->renderBox()->borderTop()) + "px"); - style->setProperty(CSSPropertyRight, String::number(-borderWidth - m_target->renderBox()->borderRight()) + "px"); - style->setProperty(CSSPropertyBottom, String::number(-borderWidth - m_target->renderBox()->borderBottom()) + "px"); - style->setProperty(CSSPropertyLeft, String::number(-borderWidth - m_target->renderBox()->borderLeft()) + "px"); - style->setProperty(CSSPropertyBorder, String::number(borderWidth) + "px solid rgba(0, 0, 0, 0.6)"); - style->setProperty(CSSPropertyWebkitBorderRadius, String::number(borderRadius) + "px"); - style->setProperty(CSSPropertyVisibility, CSSValueVisible); - - ExceptionCode ec = 0; - container->appendChild(outline.get(), ec); - ASSERT(ec == 0); - if (ec) - return; - - RefPtr<DeleteButton> button = DeleteButton::create(m_target->document()); - button->setIdAttribute(buttonElementIdentifier); - - const int buttonWidth = 30; - const int buttonHeight = 30; - const int buttonBottomShadowOffset = 2; - - style = button->getInlineStyleDecl(); - style->setProperty(CSSPropertyPosition, CSSValueAbsolute); - style->setProperty(CSSPropertyZIndex, String::number(1000000)); - style->setProperty(CSSPropertyTop, String::number((-buttonHeight / 2) - m_target->renderBox()->borderTop() - (borderWidth / 2) + buttonBottomShadowOffset) + "px"); - style->setProperty(CSSPropertyLeft, String::number((-buttonWidth / 2) - m_target->renderBox()->borderLeft() - (borderWidth / 2)) + "px"); - style->setProperty(CSSPropertyWidth, String::number(buttonWidth) + "px"); - style->setProperty(CSSPropertyHeight, String::number(buttonHeight) + "px"); - style->setProperty(CSSPropertyVisibility, CSSValueVisible); - - RefPtr<Image> buttonImage = Image::loadPlatformResource("deleteButton"); - if (buttonImage->isNull()) - return; - - button->setCachedImage(new CachedImage(buttonImage.get())); - - container->appendChild(button.get(), ec); - ASSERT(ec == 0); - if (ec) - return; - - m_containerElement = container.release(); - m_outlineElement = outline.release(); - m_buttonElement = button.release(); -} - -void DeleteButtonController::show(HTMLElement* element) -{ - hide(); - - if (!enabled() || !element || !element->inDocument() || !isDeletableElement(element)) - return; - - if (!m_frame->editor()->shouldShowDeleteInterface(static_cast<HTMLElement*>(element))) - return; - - // we rely on the renderer having current information, so we should update the layout if needed - m_frame->document()->updateLayoutIgnorePendingStylesheets(); - - m_target = element; - - if (!m_containerElement) { - createDeletionUI(); - if (!m_containerElement) { - hide(); - return; - } - } - - ExceptionCode ec = 0; - m_target->appendChild(m_containerElement.get(), ec); - ASSERT(ec == 0); - if (ec) { - hide(); - return; - } - - if (m_target->renderer()->style()->position() == StaticPosition) { - m_target->getInlineStyleDecl()->setProperty(CSSPropertyPosition, CSSValueRelative); - m_wasStaticPositioned = true; - } - - if (m_target->renderer()->style()->hasAutoZIndex()) { - m_target->getInlineStyleDecl()->setProperty(CSSPropertyZIndex, "0"); - m_wasAutoZIndex = true; - } -} - -void DeleteButtonController::hide() -{ - m_outlineElement = 0; - m_buttonElement = 0; - - ExceptionCode ec = 0; - if (m_containerElement && m_containerElement->parentNode()) - m_containerElement->parentNode()->removeChild(m_containerElement.get(), ec); - - if (m_target) { - if (m_wasStaticPositioned) - m_target->getInlineStyleDecl()->setProperty(CSSPropertyPosition, CSSValueStatic); - if (m_wasAutoZIndex) - m_target->getInlineStyleDecl()->setProperty(CSSPropertyZIndex, CSSValueAuto); - } - - m_wasStaticPositioned = false; - m_wasAutoZIndex = false; -} - -void DeleteButtonController::enable() -{ - ASSERT(m_disableStack > 0); - if (m_disableStack > 0) - m_disableStack--; - if (enabled()) { - // Determining if the element is deletable currently depends on style - // because whether something is editable depends on style, so we need - // to recalculate style before calling enclosingDeletableElement. - m_frame->document()->updateStyleIfNeeded(); - show(enclosingDeletableElement(m_frame->selection()->selection())); - } -} - -void DeleteButtonController::disable() -{ - if (enabled()) - hide(); - m_disableStack++; -} - -void DeleteButtonController::deleteTarget() -{ - if (!enabled() || !m_target) - return; - - RefPtr<Node> element = m_target; - hide(); - - // Because the deletion UI only appears when the selection is entirely - // within the target, we unconditionally update the selection to be - // a caret where the target had been. - Position pos = positionInParentBeforeNode(element.get()); - applyCommand(RemoveNodeCommand::create(element.release())); - m_frame->selection()->setSelection(VisiblePosition(pos)); -} - -} // namespace WebCore |