Example #1
0
VisiblePosition startOfParagraph(const VisiblePosition& c)
{
    Position p = c.deepEquivalent();
    Node *startNode = p.node();

    if (!startNode)
        return VisiblePosition();
    
    if (isRenderedAsNonInlineTableImageOrHR(startNode))
        return firstDeepEditingPositionForNode(startNode);

    Node* startBlock = enclosingBlock(startNode);

    Node *node = startNode;
    int offset = p.deprecatedEditingOffset();

    Node *n = startNode;
    while (n) {
        if (n->isContentEditable() != startNode->isContentEditable())
            break;
        RenderObject *r = n->renderer();
        if (!r) {
            n = n->traversePreviousNodePostOrder(startBlock);
            continue;
        }
        RenderStyle *style = r->style();
        if (style->visibility() != VISIBLE) {
            n = n->traversePreviousNodePostOrder(startBlock);
            continue;
        }
        
        if (r->isBR() || isBlock(n))
            break;
            
        if (r->isText()) {
            if (style->preserveNewline()) {
                const UChar* chars = toRenderText(r)->characters();
                int i = toRenderText(r)->textLength();
                int o = offset;
                if (n == startNode && o < i)
                    i = max(0, o);
                while (--i >= 0)
                    if (chars[i] == '\n')
                        return VisiblePosition(n, i + 1, DOWNSTREAM);
            }
            node = n;
            offset = 0;
            n = n->traversePreviousNodePostOrder(startBlock);
        } else if (editingIgnoresContent(n) || isTableElement(n)) {
            node = n;
            offset = 0;
            n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
        } else
            n = n->traversePreviousNodePostOrder(startBlock);
    }

    return VisiblePosition(node, offset, DOWNSTREAM);
}
Example #2
0
static Node* previousAncestorSiblingPostOrder(const Node& current, const Node* stayWithin)
{
    ASSERT(!current.previousSibling());
    for (Node* parent = current.parentNode(); parent; parent = parent->parentNode()) {
        if (parent == stayWithin)
            return 0;
        if (parent->previousSibling())
            return parent->previousSibling();
    }
    return 0;
}
Example #3
0
Node* NodeTraversal::previousSkippingChildren(const Node& current, const Node* stayWithin)
{
    if (current == stayWithin)
        return 0;
    if (current.previousSibling())
        return current.previousSibling();
    for (Node* parent = current.parentNode(); parent; parent = parent->parentNode()) {
        if (parent == stayWithin)
            return 0;
        if (parent->previousSibling())
            return parent->previousSibling();
    }
    return 0;
}
Example #4
0
void Element::recalcChildStyle(StyleRecalcChange change)
{
    ASSERT(document().inStyleRecalc());
    ASSERT(change >= Inherit || childNeedsStyleRecalc());
    ASSERT(!needsStyleRecalc());

    if (change > Inherit || childNeedsStyleRecalc()) {

        // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
        // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
        // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
        // See crbug.com/288225
        StyleResolver& styleResolver = document().styleResolver();
        for (Node* child = lastChild(); child; child = child->previousSibling()) {
            if (child->isTextNode()) {
                toText(child)->recalcTextStyle(change);
            } else if (child->isElementNode()) {
                Element* element = toElement(child);
                if (element->shouldCallRecalcStyle(change))
                    element->recalcStyle(change);
                else if (element->supportsStyleSharing())
                    styleResolver.addToStyleSharingList(*element);
            }
        }
    }
}
RenderObject* NodeRenderingContext::previousRenderer() const
{
    ASSERT(m_node->renderer() || m_location != LocationUndetermined);
    if (RenderObject* renderer = m_node->renderer())
        return renderer->previousSibling();

    if (m_parentFlowRenderer)
        return m_parentFlowRenderer->previousRendererForNode(m_node);

    if (m_phase == AttachContentForwarded) {
        if (RenderObject* found = previousRendererOf(m_includer, m_node))
            return found;
        return NodeRenderingContext(m_includer).previousRenderer();
    }

    // FIXME: We should have the same O(N^2) avoidance as nextRenderer does
    // however, when I tried adding it, several tests failed.
    for (Node* node = m_node->previousSibling(); node; node = node->previousSibling()) {
        if (node->renderer()) {
            // Do not return elements that are attached to a different flow-thread.
            if (node->renderer()->style() && !node->renderer()->style()->flowThread().isEmpty())
                continue;
            return node->renderer();
        }
        if (node->isContentElement()) {
            if (RenderObject* last = lastRendererOf(toHTMLContentElement(node)))
                return last;
        }
    }

    if (m_phase == AttachContentFallback)
        return NodeRenderingContext(m_node->parentNode()).previousRenderer();

    return 0;
}
Example #6
0
void ShadowRoot::recalcStyle(StyleRecalcChange change)
{
    // ShadowRoot doesn't support custom callbacks.
    ASSERT(!hasCustomStyleCallbacks());

    StyleResolverParentScope parentScope(*this);

    if (styleChangeType() >= SubtreeStyleChange)
        change = Force;

    if (change < Force && hasRareData() && childNeedsStyleRecalc())
        checkForChildrenAdjacentRuleChanges();

    // There's no style to update so just calling recalcStyle means we're updated.
    clearNeedsStyleRecalc();

    // FIXME: This doesn't handle :hover + div properly like Element::recalcStyle does.
    Text* lastTextNode = 0;
    for (Node* child = lastChild(); child; child = child->previousSibling()) {
        if (child->isTextNode()) {
            toText(child)->recalcTextStyle(change, lastTextNode);
            lastTextNode = toText(child);
        } else if (child->isElementNode()) {
            if (child->shouldCallRecalcStyle(change))
                toElement(child)->recalcStyle(change, lastTextNode);
            if (child->renderer())
                lastTextNode = 0;
        }
    }

    clearChildNeedsStyleRecalc();
}
Example #7
0
Node* InsertionPoint::previousDistributedTo(const Node* node) const
{
    for (Node* current = node->previousSibling(); current; current = current->previousSibling()) {
        if (matchTypeFor(current) == InsertionPoint::AlwaysMatches)
            return current;
    }
    return 0;
}
Example #8
0
HTMLTableSectionElement* HTMLTableElement::lastBody() const
{
    for (Node* child = lastChild(); child; child = child->previousSibling()) {
        if (child->hasTagName(tbodyTag))
            return static_cast<HTMLTableSectionElement*>(child);
    }
    return 0;
}
Node* ChildNodeList::traverseBackwardToOffset(unsigned offset, Node& currentNode, unsigned& currentOffset) const
{
    ASSERT(currentOffset > offset);
    for (Node* previous = currentNode.previousSibling(); previous; previous = previous->previousSibling()) {
        if (--currentOffset == offset)
            return previous;
    }
    return 0;
}
Example #10
0
Node* InsertionPoint::lastDistributed() const
{
    if (!m_hasDistribution)
        return 0;
    for (Node* current = shadowHost()->lastChild(); current; current = current->previousSibling()) {
        if (matchTypeFor(current) == InsertionPoint::AlwaysMatches)
            return current;
    }
    return 0;
}
Example #11
0
Node* TreeWalker::lastChild()
{
	if (!_pCurrent) return 0;

	Node* pNode = accept(_pCurrent) != NodeFilter::FILTER_REJECT ? _pCurrent->lastChild() : 0;
	while (pNode && accept(pNode) != NodeFilter::FILTER_ACCEPT)
		pNode = pNode->previousSibling();
	if (pNode)
		_pCurrent = pNode;
	return pNode;
}
Example #12
0
Node* TreeWalker::previousSibling()
{
	if (!_pCurrent) return 0;

	Node* pNode = _pCurrent->previousSibling();
	while (pNode && accept(pNode) != NodeFilter::FILTER_ACCEPT)
		pNode = pNode->previousSibling();
	if (pNode)
		_pCurrent = pNode;
	return pNode;
}
Example #13
0
/*!
    Returns the element's previous sibling.

    \sa firstChild(), nextSibling(), lastChild()
*/
QWebElement QWebElement::previousSibling() const
{
    if (!m_element)
        return QWebElement();
    for (Node* sib = m_element->previousSibling(); sib; sib = sib->previousSibling()) {
        if (!sib->isElementNode())
            continue;
        Element* e = static_cast<Element*>(sib);
        return QWebElement(e);
    }
    return QWebElement();
}
Example #14
0
/*!
    Returns the element's last child.

    \sa firstChild(), previousSibling(), nextSibling()
*/
QWebElement QWebElement::lastChild() const
{
    if (!m_element)
        return QWebElement();
    for (Node* child = m_element->lastChild(); child; child = child->previousSibling()) {
        if (!child->isElementNode())
            continue;
        Element* e = static_cast<Element*>(child);
        return QWebElement(e);
    }
    return QWebElement();
}
Node* ChildNodeList::item(unsigned index) const
{
    unsigned int pos = 0;
    Node* n = m_rootNode->firstChild();

    if (m_caches->isItemCacheValid) {
        if (index == m_caches->lastItemOffset)
            return m_caches->lastItem;
        
        int diff = index - m_caches->lastItemOffset;
        unsigned dist = abs(diff);
        if (dist < index) {
            n = m_caches->lastItem;
            pos = m_caches->lastItemOffset;
        }
    }

    if (m_caches->isLengthCacheValid) {
        if (index >= m_caches->cachedLength)
            return 0;

        int diff = index - pos;
        unsigned dist = abs(diff);
        if (dist > m_caches->cachedLength - 1 - index) {
            n = m_rootNode->lastChild();
            pos = m_caches->cachedLength - 1;
        }
    }

    if (pos <= index) {
        while (n && pos < index) {
            n = n->nextSibling();
            ++pos;
        }
    } else {
        while (n && pos > index) {
            n = n->previousSibling();
            --pos;
        }
    }

    if (n) {
        m_caches->lastItem = n;
        m_caches->lastItemOffset = pos;
        m_caches->isItemCacheValid = true;
        return n;
    }

    return 0;
}
void ExtensionPointService::handleExtensions(Bundle::ConstPtr pBundle, std::istream& istr, GenericHandler handler, Direction dir)
{
	Poco::XML::DOMParser parser;
	parser.setFeature(Poco::XML::XMLReader::FEATURE_NAMESPACES, false);
	parser.setFeature(Poco::XML::DOMParser::FEATURE_FILTER_WHITESPACE, true);
	Poco::XML::InputSource source(istr);
	AutoPtr<Document> pDoc(parser.parse(&source));
	Node* pRoot = pDoc->firstChild();
	while (pRoot && pRoot->nodeName() != EXTENSIONS_ELEM)
	{
		pRoot = pRoot->nextSibling();
	}
	if (pRoot)
	{
		Node* pNode = (dir == DIR_FORWARD ? pRoot->firstChild() : pRoot->lastChild());
		while (pNode)
		{
			if (pNode->nodeType() == Node::ELEMENT_NODE)
			{
				if (pNode->nodeName() == EXTENSION_ELEM)
				{
					Element* pElem = static_cast<Element*>(pNode);
					const std::string& id = pElem->getAttribute(POINT_ATTR);
					if (!id.empty())
					{
						(this->*handler)(pBundle, id, pElem);
					}
					else
					{
						_logger.error(std::string("No point attribute found in extension element of bundle ")
							+ pBundle->symbolicName());
					}
				}
				else
				{
					_logger.warning(std::string("Unsupported element '")
						+ pNode->nodeName()
						+ "' found in "
						+ EXTENSIONS_XML
						+ " of bundle "
						+ pBundle->symbolicName());
				}
			}

			pNode = (dir == DIR_FORWARD ? pNode->nextSibling() : pNode->previousSibling());
		}
	}
	else throw Poco::NotFoundException("No extensions element found");
}
Example #17
0
void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild)
{
    NoEventDispatchAssertion assertNoEventDispatch;

    ASSERT(!newChild.parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
    ASSERT(!newChild.nextSibling());
    ASSERT(!newChild.previousSibling());
    ASSERT(!newChild.isShadowRoot());

    Node* prev = nextChild.previousSibling();
    ASSERT(m_lastChild != prev);
    nextChild.setPreviousSibling(&newChild);
    if (prev) {
        ASSERT(m_firstChild != &nextChild);
        ASSERT(prev->nextSibling() == &nextChild);
        prev->setNextSibling(&newChild);
    } else {
        ASSERT(m_firstChild == &nextChild);
        m_firstChild = &newChild;
    }
    newChild.setParentNode(this);
    newChild.setPreviousSibling(prev);
    newChild.setNextSibling(&nextChild);
}
Example #18
0
void RenderMathMLFenced::addChild(RenderObject* child, RenderObject* beforeChild)
{
    // make the fences if the render object is empty
    if (isEmpty())
        updateFromElement();
    
    // FIXME: Adding or removing a child should possibly cause all later separators to shift places if they're different, as later child positions change by +1 or -1. This should also handle surrogate pairs. See https://bugs.webkit.org/show_bug.cgi?id=125938.
    
    RenderPtr<RenderMathMLOperator> separatorRenderer;
    if (m_separators.get()) {
        unsigned int count = 0;
        for (Node* position = child->node(); position; position = position->previousSibling()) {
            if (position->isElementNode())
                count++;
        }
        if (!beforeChild) {
            // We're adding at the end (before the closing fence), so a new separator would go before the new child, not after it.
            --count;
        }
        // |count| is now the number of element children that will be before our new separator, i.e. it's the 1-based index of the separator.
        
        if (count > 0) {
            UChar separator;
            
            // Use the last separator if we've run out of specified separators.
            if (count > m_separators.get()->length())
                separator = (*m_separators.get())[m_separators.get()->length() - 1];
            else
                separator = (*m_separators.get())[count - 1];
                
            StringBuilder builder;
            builder.append(separator);
            separatorRenderer = createMathMLOperator(builder.toString(), MathMLOperatorDictionary::Infix, MathMLOperatorDictionary::Separator);
        }
    }
    
    if (beforeChild) {
        // Adding |x| before an existing |y| e.g. in element (y) - first insert our new child |x|, then its separator, to get (x, y).
        RenderMathMLRow::addChild(child, beforeChild);
        if (separatorRenderer)
            RenderMathMLRow::addChild(separatorRenderer.leakPtr(), beforeChild);
    } else {
        // Adding |y| at the end of an existing element e.g. (x) - insert the separator first before the closing fence, then |y|, to get (x, y).
        if (separatorRenderer)
            RenderMathMLRow::addChild(separatorRenderer.leakPtr(), m_closeFenceRenderer);
        RenderMathMLRow::addChild(child, m_closeFenceRenderer);
    }
}
Example #19
0
void SVGFontFaceElement::rebuildFontFace()
{
    if (!inDocument()) {
        ASSERT(!m_fontElement);
        return;
    }

    bool describesParentFont = parentNode()->hasTagName(SVGNames::fontTag);
    RefPtr<CSSValueList> list;

    if (describesParentFont) {
        m_fontElement = toSVGFontElement(parentNode());

        list = CSSValueList::createCommaSeparated();
        list->append(CSSFontFaceSrcValue::createLocal(fontFamily()));
    } else {
        m_fontElement = 0;
        // we currently ignore all but the last src element, alternatively we could concat them
        for (Node* child = lastChild(); child && !list; child = child->previousSibling()) {
            if (child->hasTagName(font_face_srcTag)) {
                list = toSVGFontFaceSrcElement(child)->srcValue();
                break;
            }
        }
    }

    if (!list || !list->length())
        return;

    // Parse in-memory CSS rules
    m_fontFaceRule->mutableProperties()->addParsedProperty(CSSProperty(CSSPropertySrc, list));

    if (describesParentFont) {
        // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
        RefPtr<CSSValue> src = m_fontFaceRule->properties()->getPropertyCSSValue(CSSPropertySrc);
        CSSValueList* srcList = toCSSValueList(src.get());

        unsigned srcLength = srcList ? srcList->length() : 0;
        for (unsigned i = 0; i < srcLength; i++) {
            if (CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->itemWithoutBoundsCheck(i)))
                item->setSVGFontFaceElement(this);
        }
    }

    document().styleResolverChanged(RecalcStyleDeferred);
}
Example #20
0
void ContainerNode::parserRemoveChild(Node& oldChild)
{
    ASSERT(oldChild.parentNode() == this);
    ASSERT(!oldChild.isDocumentFragment());

    Node* prev = oldChild.previousSibling();
    Node* next = oldChild.nextSibling();

    oldChild.updateAncestorConnectedSubframeCountForRemoval();

    ChildListMutationScope(*this).willRemoveChild(oldChild);
    oldChild.notifyMutationObserversNodeWillDetach();

    removeBetween(prev, next, oldChild);

    notifyChildRemoved(oldChild, prev, next, ChildChangeSourceParser);

    ChildNodeRemovalNotifier(*this).notify(oldChild);
}
Example #21
0
void RenderMathMLFenced::addChild(RenderObject* child, RenderObject*)
{
    // make the fences if the render object is empty
    if (isEmpty())
        updateFromElement();
    
    if (m_separators.get()) {
        unsigned int count = 0;
        for (Node* position = child->node(); position; position = position->previousSibling()) {
            if (position->nodeType() == Node::ELEMENT_NODE)
                count++;
        }
                
        if (count > 1) {
            UChar separator;
            
            // Use the last separator if we've run out of specified separators.
            if ((count - 1) >= m_separators.get()->length())
                separator = (*m_separators.get())[m_separators.get()->length() - 1];
            else
                separator = (*m_separators.get())[count - 1];
                
            RenderObject* separatorObj = new (renderArena()) RenderMathMLOperator(node(), separator);
            separatorObj->setStyle(makeOperatorStyle().release());
            RenderBlock::addChild(separatorObj, lastChild());
        }
    }
    
    // If we have a block, we'll wrap it in an inline-block.
    if (child->isBlockFlow() && child->style()->display() != INLINE_BLOCK) {
        // Block objects wrapper.

        RenderBlock* block = new (renderArena()) RenderBlock(node());
        RefPtr<RenderStyle> newStyle = RenderStyle::create();
        newStyle->inheritFrom(style());
        newStyle->setDisplay(INLINE_BLOCK);
        block->setStyle(newStyle.release());
        
        RenderBlock::addChild(block, lastChild());
        block->addChild(child);    
    } else
        RenderBlock::addChild(child, lastChild());
}
Example #22
0
void ShadowRoot::recalcStyle(StyleRecalcChange change)
{
    if (styleChangeType() >= SubtreeStyleChange)
        change = Force;

    // There's no style to update so just calling recalcStyle means we're updated.
    clearNeedsStyleRecalc();

    for (Node* child = lastChild(); child; child = child->previousSibling()) {
        if (child->isTextNode()) {
            toText(child)->recalcTextStyle(change);
        } else if (child->isElementNode()) {
            if (child->shouldCallRecalcStyle(change))
                toElement(child)->recalcStyle(change);
        }
    }

    clearChildNeedsStyleRecalc();
}
void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows()
{
    if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow) {
        Node* row = m_endTableRow->previousSibling();
        while (row && row != m_startTableRow) {
            RefPtr<Node> previousRow = row->previousSibling();
            if (isTableRowEmpty(row))
                // Use a raw removeNode, instead of DeleteSelectionCommand's, because
                // that won't remove rows, it only empties them in preparation for this function.
                CompositeEditCommand::removeNode(row);
            row = previousRow.get();
        }
    }
    
    // Remove empty rows after the start row.
    if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m_endTableRow) {
        Node* row = m_startTableRow->nextSibling();
        while (row && row != m_endTableRow) {
            RefPtr<Node> nextRow = row->nextSibling();
            if (isTableRowEmpty(row))
                CompositeEditCommand::removeNode(row);
            row = nextRow.get();
        }
    }
    
    if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow)
        if (isTableRowEmpty(m_endTableRow.get())) {
            // Don't remove m_endTableRow if it's where we're putting the ending selection.
            if (!m_endingPosition.deprecatedNode()->isDescendantOf(m_endTableRow.get())) {
                // FIXME: We probably shouldn't remove m_endTableRow unless it's fully selected, even if it is empty.
                // We'll need to start adjusting the selection endpoints during deletion to know whether or not m_endTableRow
                // was fully selected here.
                CompositeEditCommand::removeNode(m_endTableRow.get());
            }
        }
}
Example #24
0
// Result nodes are ordered in axis order. Node test (including merged predicates) is applied.
void Step::nodesInAxis(Node* context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
        case ChildAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->nextSibling())
                if (nodeMatches(n, ChildAxis, m_nodeTest))
                    nodes.append(n);
            return;
        case DescendantAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context))
                if (nodeMatches(n, DescendantAxis, m_nodeTest))
                    nodes.append(n);
            return;
        case ParentAxis:
            if (context->isAttributeNode()) {
                Element* n = toAttr(context)->ownerElement();
                if (nodeMatches(n, ParentAxis, m_nodeTest))
                    nodes.append(n);
            } else {
                ContainerNode* n = context->parentNode();
                if (n && nodeMatches(n, ParentAxis, m_nodeTest))
                    nodes.append(n);
            }
            return;
        case AncestorAxis: {
            Node* n = context;
            if (context->isAttributeNode()) {
                n = toAttr(context)->ownerElement();
                if (nodeMatches(n, AncestorAxis, m_nodeTest))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n, AncestorAxis, m_nodeTest))
                    nodes.append(n);
            nodes.markSorted(false);
            return;
        }
        case FollowingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
                return;

            for (Node* n = context->nextSibling(); n; n = n->nextSibling())
                if (nodeMatches(n, FollowingSiblingAxis, m_nodeTest))
                    nodes.append(n);
            return;
        case PrecedingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
                return;

            for (Node* n = context->previousSibling(); n; n = n->previousSibling())
                if (nodeMatches(n, PrecedingSiblingAxis, m_nodeTest))
                    nodes.append(n);

            nodes.markSorted(false);
            return;
        case FollowingAxis:
            if (context->isAttributeNode()) {
                Node* p = toAttr(context)->ownerElement();
                while ((p = NodeTraversal::next(*p))) {
                    if (nodeMatches(p, FollowingAxis, m_nodeTest))
                        nodes.append(p);
                }
            } else {
                for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                    for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
                        if (nodeMatches(n, FollowingAxis, m_nodeTest))
                            nodes.append(n);
                        for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n))
                            if (nodeMatches(c, FollowingAxis, m_nodeTest))
                                nodes.append(c);
                    }
                }
            }
            return;
        case PrecedingAxis: {
            if (context->isAttributeNode())
                context = toAttr(context)->ownerElement();

            Node* n = context;
            while (ContainerNode* parent = n->parentNode()) {
                for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n))
                    if (nodeMatches(n, PrecedingAxis, m_nodeTest))
                        nodes.append(n);
                n = parent;
            }
            nodes.markSorted(false);
            return;
        }
        case AttributeAxis: {
            if (!context->isElementNode())
                return;

            Element* contextElement = toElement(context);

            // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
            if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) {
                RefPtr<Node> n = contextElement->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
                if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
                    if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
                        nodes.append(n.release());
                }
                return;
            }

            if (!contextElement->hasAttributes())
                return;

            for (unsigned i = 0; i < contextElement->attributeCount(); ++i) {
                RefPtr<Attr> attr = contextElement->ensureAttr(contextElement->attributeItem(i)->name());
                if (nodeMatches(attr.get(), AttributeAxis, m_nodeTest))
                    nodes.append(attr.release());
            }
            return;
        }
        case NamespaceAxis:
            // XPath namespace nodes are not implemented yet.
            return;
        case SelfAxis:
            if (nodeMatches(context, SelfAxis, m_nodeTest))
                nodes.append(context);
            return;
        case DescendantOrSelfAxis:
            if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest))
                nodes.append(context);
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context))
            if (nodeMatches(n, DescendantOrSelfAxis, m_nodeTest))
                nodes.append(n);
            return;
        case AncestorOrSelfAxis: {
            if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest))
                nodes.append(context);
            Node* n = context;
            if (context->isAttributeNode()) {
                n = toAttr(context)->ownerElement();
                if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest))
                    nodes.append(n);

            nodes.markSorted(false);
            return;
        }
    }
    ASSERT_NOT_REACHED();
}
Example #25
0
bool Text::textRendererIsNeeded(const RenderStyle& style, const RenderObject& parent)
{
    if (isEditingText())
        return true;

    if (!length())
        return false;

    if (style.display() == NONE)
        return false;

    if (style.requiresOnlyBlockChildren())
        return false;

    if (!containsOnlyWhitespace())
        return true;

    if (!parent.canHaveWhitespaceChildren())
        return false;

    if (style.preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
        return true;

    RenderObject* prev;
    for (Node* sibling = this->previousSibling(); sibling; sibling = sibling->previousSibling()) {
        if ((prev = sibling->renderer()))
            break;
    }

    if (parent.isRenderInline()) {
        // <span><div/> <div/></span>
        if (prev && !prev->isInline())
            return false;
    } else {
        if (parent.isRenderBlock() && !parent.isRenderParagraph() && (!prev || !prev->isInline()))
            return false;

        // Avoiding creation of a Renderer for the text node is a non-essential memory optimization.
        // So to avoid blowing up on very wide DOMs, we limit the number of siblings to visit.
        unsigned maxSiblingsToVisit = 50;

        RenderObject* first = parent.slowFirstChild();
        while (first && first->isFloatingOrOutOfFlowPositioned() && maxSiblingsToVisit--)
            first = first->nextSibling();

        if (!first) {
            // If the block has nothing but white-space we ignore it
            return false;
        }

        for (Node* sibling = this->nextSibling(); sibling; sibling = sibling->nextSibling()) {
            if (RenderObject* nextRenderer = sibling->renderer()) {
                if (nextRenderer == first) {
                    // Whitespace at the start of a block just goes away.  Don't even
                    // make a render object for this text.
                    return false;
                }
                break;
            }
        }

    }
    return true;
}
Example #26
0
JSValue* JSNode::getValueProperty(ExecState* exec, int token) const
{
    switch (token) {
    case NodeNameAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->nodeName());
    }
    case NodeValueAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->nodeValue());
    }
    case NodeTypeAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsNumber(exec, imp->nodeType());
    }
    case ParentNodeAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->parentNode()));
    }
    case ChildNodesAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->childNodes()));
    }
    case FirstChildAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->firstChild()));
    }
    case LastChildAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->lastChild()));
    }
    case PreviousSiblingAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->previousSibling()));
    }
    case NextSiblingAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->nextSibling()));
    }
    case AttributesAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->attributes()));
    }
    case OwnerDocumentAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->ownerDocument()));
    }
    case NamespaceURIAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->namespaceURI());
    }
    case PrefixAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->prefix());
    }
    case LocalNameAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->localName());
    }
    case BaseURIAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->baseURI());
    }
    case TextContentAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return jsStringOrNull(exec, imp->textContent());
    }
    case ParentElementAttrNum: {
        Node* imp = static_cast<Node*>(impl());
        return toJS(exec, WTF::getPtr(imp->parentElement()));
    }
    case ConstructorAttrNum:
        return getConstructor(exec);
    }
    return 0;
}
Example #27
0
void Step::nodesInAxis(Node* context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
        case ChildAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->nextSibling())
                if (nodeMatches(n))
                    nodes.append(n);
            return;
        case DescendantAxis:
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
                if (nodeMatches(n))
                    nodes.append(n);
            return;
        case ParentAxis:
            if (context->isAttributeNode()) {
                Node* n = static_cast<Attr*>(context)->ownerElement();
                if (nodeMatches(n))
                    nodes.append(n);
            } else {
                Node* n = context->parentNode();
                if (n && nodeMatches(n))
                    nodes.append(n);
            }
            return;
        case AncestorAxis: {
            Node* n = context;
            if (context->isAttributeNode()) {
                n = static_cast<Attr*>(context)->ownerElement();
                if (nodeMatches(n))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n))
                    nodes.append(n);
            nodes.reverse();
            return;
        }
        case FollowingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE) 
                return;
            
            for (Node* n = context->nextSibling(); n; n = n->nextSibling())
                if (nodeMatches(n))
                    nodes.append(n);
            return;
        case PrecedingSiblingAxis:
            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
                return;
            
            for (Node* n = context->previousSibling(); n; n = n->previousSibling())
                if (nodeMatches(n))
                    nodes.append(n);

            nodes.reverse();
            return;
        case FollowingAxis:
            if (context->isAttributeNode()) {
                Node* p = static_cast<Attr*>(context)->ownerElement();
                while ((p = p->traverseNextNode()))
                    if (nodeMatches(p))
                        nodes.append(p);
            } else {
                for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                    for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
                        if (nodeMatches(n))
                            nodes.append(n);
                        for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
                            if (nodeMatches(c))
                                nodes.append(c);
                    }
                }
            }
            return;
        case PrecedingAxis:
            if (context->isAttributeNode())
                context = static_cast<Attr*>(context)->ownerElement();

            for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                for (Node* n = p->previousSibling(); n ; n = n->previousSibling()) {
                    if (nodeMatches(n))
                        nodes.append(n);
                    for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
                        if (nodeMatches(c))
                            nodes.append(c);
                }
            }
            nodes.markSorted(false);
            return;
        case AttributeAxis: {
            if (context->nodeType() != Node::ELEMENT_NODE)
                return;

            // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
            if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != "*") {
                RefPtr<Node> n = static_cast<Element*>(context)->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
                if (n && n->namespaceURI() != "http://www.w3.org/2000/xmlns/") // In XPath land, namespace nodes are not accessible on the attribute axis.
                    nodes.append(n.release());
                return;
            }
            
            NamedAttrMap* attrs = context->attributes();
            if (!attrs)
                return;

            for (unsigned long i = 0; i < attrs->length(); ++i) {
                RefPtr<Node> n = attrs->item(i);
                if (nodeMatches(n.get()))
                    nodes.append(n.release());
            }
            return;
        }
        case NamespaceAxis:
            // XPath namespace nodes are not implemented yet.
            return;
        case SelfAxis:
            if (nodeMatches(context))
                nodes.append(context);
            return;
        case DescendantOrSelfAxis:
            if (nodeMatches(context))
                nodes.append(context);
            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
                return;

            for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
            if (nodeMatches(n))
                nodes.append(n);
            return;
        case AncestorOrSelfAxis: {
            if (nodeMatches(context))
                nodes.append(context);
            Node* n = context;
            if (context->isAttributeNode()) {
                n = static_cast<Attr*>(context)->ownerElement();
                if (nodeMatches(n))
                    nodes.append(n);
            }
            for (n = n->parentNode(); n; n = n->parentNode())
                if (nodeMatches(n))
                    nodes.append(n);

            nodes.reverse();
            return;
        }
    }
    ASSERT_NOT_REACHED();
}
Example #28
0
static v8::Handle<v8::Value> previousSiblingAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.Node.previousSibling._get");
    Node* imp = V8Node::toNative(info.Holder());
    return toV8(imp->previousSibling());
}
Example #29
0
// Result nodes are ordered in axis order. Node test (including merged
// predicates) is applied.
void Step::nodesInAxis(EvaluationContext& evaluationContext, Node* context, NodeSet& nodes) const
{
    ASSERT(nodes.isEmpty());
    switch (m_axis) {
    case ChildAxis:
        // In XPath model, attribute nodes do not have children.
        if (context->isAttributeNode())
            return;

        for (Node* n = context->firstChild(); n; n = n->nextSibling()) {
            if (nodeMatches(evaluationContext, n, ChildAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case DescendantAxis:
        // In XPath model, attribute nodes do not have children.
        if (context->isAttributeNode())
            return;

        for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) {
            if (nodeMatches(evaluationContext, n, DescendantAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case ParentAxis:
        if (context->isAttributeNode()) {
            Element* n = toAttr(context)->ownerElement();
            if (nodeMatches(evaluationContext, n, ParentAxis, nodeTest()))
                nodes.append(n);
        } else {
            ContainerNode* n = context->parentNode();
            if (n && nodeMatches(evaluationContext, n, ParentAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case AncestorAxis: {
        Node* n = context;
        if (context->isAttributeNode()) {
            n = toAttr(context)->ownerElement();
            if (nodeMatches(evaluationContext, n, AncestorAxis, nodeTest()))
                nodes.append(n);
        }
        for (n = n->parentNode(); n; n = n->parentNode()) {
            if (nodeMatches(evaluationContext, n, AncestorAxis, nodeTest()))
                nodes.append(n);
        }
        nodes.markSorted(false);
        return;
    }

    case FollowingSiblingAxis:
        if (context->nodeType() == Node::ATTRIBUTE_NODE)
            return;

        for (Node* n = context->nextSibling(); n; n = n->nextSibling()) {
            if (nodeMatches(evaluationContext, n, FollowingSiblingAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case PrecedingSiblingAxis:
        if (context->nodeType() == Node::ATTRIBUTE_NODE)
            return;

        for (Node* n = context->previousSibling(); n; n = n->previousSibling()) {
            if (nodeMatches(evaluationContext, n, PrecedingSiblingAxis, nodeTest()))
                nodes.append(n);
        }
        nodes.markSorted(false);
        return;

    case FollowingAxis:
        if (context->isAttributeNode()) {
            for (Node* p = NodeTraversal::next(*toAttr(context)->ownerElement()); p; p = NodeTraversal::next(*p)) {
                if (nodeMatches(evaluationContext, p, FollowingAxis, nodeTest()))
                    nodes.append(p);
            }
        } else {
            for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
                for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
                    if (nodeMatches(evaluationContext, n, FollowingAxis, nodeTest()))
                        nodes.append(n);
                    for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n)) {
                        if (nodeMatches(evaluationContext, c, FollowingAxis, nodeTest()))
                            nodes.append(c);
                    }
                }
            }
        }
        return;

    case PrecedingAxis: {
        if (context->isAttributeNode())
            context = toAttr(context)->ownerElement();

        Node* n = context;
        while (ContainerNode* parent = n->parentNode()) {
            for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n)) {
                if (nodeMatches(evaluationContext, n, PrecedingAxis, nodeTest()))
                    nodes.append(n);
            }
            n = parent;
        }
        nodes.markSorted(false);
        return;
    }

    case AttributeAxis: {
        if (!context->isElementNode())
            return;

        Element* contextElement = toElement(context);
        // Avoid lazily creating attribute nodes for attributes that we do not
        // need anyway.
        if (nodeTest().kind() == NodeTest::NameTest && nodeTest().data() != starAtom) {
            RefPtrWillBeRawPtr<Node> n = contextElement->getAttributeNodeNS(nodeTest().namespaceURI(), nodeTest().data());
            // In XPath land, namespace nodes are not accessible on the attribute axis.
            if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) {
                // Still need to check merged predicates.
                if (nodeMatches(evaluationContext, n.get(), AttributeAxis, nodeTest()))
                    nodes.append(n.release());
            }
            return;
        }

        AttributeCollection attributes = contextElement->attributes();
        AttributeCollection::iterator end = attributes.end();
        for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
            RefPtrWillBeRawPtr<Attr> attr = contextElement->ensureAttr(it->name());
            if (nodeMatches(evaluationContext, attr.get(), AttributeAxis, nodeTest()))
                nodes.append(attr.release());
        }
        return;
    }

    case NamespaceAxis:
        // XPath namespace nodes are not implemented.
        return;

    case SelfAxis:
        if (nodeMatches(evaluationContext, context, SelfAxis, nodeTest()))
            nodes.append(context);
        return;

    case DescendantOrSelfAxis:
        if (nodeMatches(evaluationContext, context, DescendantOrSelfAxis, nodeTest()))
            nodes.append(context);
        // In XPath model, attribute nodes do not have children.
        if (context->isAttributeNode())
            return;

        for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) {
            if (nodeMatches(evaluationContext, n, DescendantOrSelfAxis, nodeTest()))
                nodes.append(n);
        }
        return;

    case AncestorOrSelfAxis: {
        if (nodeMatches(evaluationContext, context, AncestorOrSelfAxis, nodeTest()))
            nodes.append(context);
        Node* n = context;
        if (context->isAttributeNode()) {
            n = toAttr(context)->ownerElement();
            if (nodeMatches(evaluationContext, n, AncestorOrSelfAxis, nodeTest()))
                nodes.append(n);
        }
        for (n = n->parentNode(); n; n = n->parentNode()) {
            if (nodeMatches(evaluationContext, n, AncestorOrSelfAxis, nodeTest()))
                nodes.append(n);
        }
        nodes.markSorted(false);
        return;
    }
    }
    ASSERT_NOT_REACHED();
}
void InsertListCommand::doApply()
{
    if (endingSelection().isNone())
        return;
    
    if (!endingSelection().rootEditableElement())
        return;
    
    VisiblePosition visibleEnd = endingSelection().visibleEnd();
    VisiblePosition visibleStart = endingSelection().visibleStart();
    // When a selection ends at the start of a paragraph, we rarely paint 
    // the selection gap before that paragraph, because there often is no gap.  
    // In a case like this, it's not obvious to the user that the selection 
    // ends "inside" that paragraph, so it would be confusing if InsertUn{Ordered}List 
    // operated on that paragraph.
    // FIXME: We paint the gap before some paragraphs that are indented with left 
    // margin/padding, but not others.  We should make the gap painting more consistent and 
    // then use a left margin/padding rule here.
    if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
        setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(true)));

    if (endingSelection().isRange() && modifyRange())
        return;
    
    // FIXME: This will produce unexpected results for a selection that starts just before a
    // table and ends inside the first cell, selectionForParagraphIteration should probably
    // be renamed and deployed inside setEndingSelection().
    Node* selectionNode = endingSelection().start().node();
    const QualifiedName listTag = (m_type == OrderedList) ? olTag : ulTag;
    Node* listChildNode = enclosingListChild(selectionNode);
    bool switchListType = false;
    if (listChildNode) {
        // Remove the list chlild.
        HTMLElement* listNode = enclosingList(listChildNode);
        if (!listNode)
            listNode = fixOrphanedListChild(listChildNode);
        if (!listNode->hasTagName(listTag))
            // listChildNode will be removed from the list and a list of type m_type will be created.
            switchListType = true;
        Node* nextListChild;
        Node* previousListChild;
        VisiblePosition start;
        VisiblePosition end;
        if (listChildNode->hasTagName(liTag)) {
            start = firstDeepEditingPositionForNode(listChildNode);
            end = lastDeepEditingPositionForNode(listChildNode);
            nextListChild = listChildNode->nextSibling();
            previousListChild = listChildNode->previousSibling();
        } else {
            // A paragraph is visually a list item minus a list marker.  The paragraph will be moved.
            start = startOfParagraph(endingSelection().visibleStart());
            end = endOfParagraph(endingSelection().visibleEnd());
            nextListChild = enclosingListChild(end.next().deepEquivalent().node());
            ASSERT(nextListChild != listChildNode);
            if (enclosingList(nextListChild) != listNode)
                nextListChild = 0;
            previousListChild = enclosingListChild(start.previous().deepEquivalent().node());
            ASSERT(previousListChild != listChildNode);
            if (enclosingList(previousListChild) != listNode)
                previousListChild = 0;
        }
        // When removing a list, we must always create a placeholder to act as a point of insertion
        // for the list content being removed.
        RefPtr<Element> placeholder = createBreakElement(document());
        RefPtr<Element> nodeToInsert = placeholder;
        // If the content of the list item will be moved into another list, put it in a list item
        // so that we don't create an orphaned list child.
        if (enclosingList(listNode)) {
            nodeToInsert = createListItemElement(document());
            appendNode(placeholder, nodeToInsert);
        }
        
        if (nextListChild && previousListChild) {
            // We want to pull listChildNode out of listNode, and place it before nextListChild 
            // and after previousListChild, so we split listNode and insert it between the two lists.  
            // But to split listNode, we must first split ancestors of listChildNode between it and listNode,
            // if any exist.
            // FIXME: We appear to split at nextListChild as opposed to listChildNode so that when we remove
            // listChildNode below in moveParagraphs, previousListChild will be removed along with it if it is 
            // unrendered. But we ought to remove nextListChild too, if it is unrendered.
            splitElement(listNode, splitTreeToNode(nextListChild, listNode));
            insertNodeBefore(nodeToInsert, listNode);
        } else if (nextListChild || listChildNode->parentNode() != listNode) {
            // Just because listChildNode has no previousListChild doesn't mean there isn't any content
            // in listNode that comes before listChildNode, as listChildNode could have ancestors
            // between it and listNode. So, we split up to listNode before inserting the placeholder
            // where we're about to move listChildNode to.
            if (listChildNode->parentNode() != listNode)
                splitElement(listNode, splitTreeToNode(listChildNode, listNode).get());
            insertNodeBefore(nodeToInsert, listNode);
        } else
            insertNodeAfter(nodeToInsert, listNode);
        
        VisiblePosition insertionPoint = VisiblePosition(Position(placeholder.get(), 0));
        moveParagraphs(start, end, insertionPoint, true);
    }
    if (!listChildNode || switchListType || m_forceCreateList) {
        // Create list.
        VisiblePosition originalStart = endingSelection().visibleStart();
        VisiblePosition start = startOfParagraph(originalStart);
        VisiblePosition end = endOfParagraph(endingSelection().visibleEnd());
        
        // Check for adjoining lists.
        VisiblePosition previousPosition = start.previous(true);
        VisiblePosition nextPosition = end.next(true);
        RefPtr<HTMLElement> listItemElement = createListItemElement(document());
        RefPtr<HTMLElement> placeholder = createBreakElement(document());
        appendNode(placeholder, listItemElement);
        Element* previousList = outermostEnclosingList(previousPosition.deepEquivalent().node());
        Element* nextList = outermostEnclosingList(nextPosition.deepEquivalent().node());
        Node* startNode = start.deepEquivalent().node();
        Node* previousCell = enclosingTableCell(previousPosition.deepEquivalent());
        Node* nextCell = enclosingTableCell(nextPosition.deepEquivalent());
        Node* currentCell = enclosingTableCell(start.deepEquivalent());
        if (previousList && (!previousList->hasTagName(listTag) || startNode->isDescendantOf(previousList) || previousCell != currentCell))
            previousList = 0;
        if (nextList && (!nextList->hasTagName(listTag) || startNode->isDescendantOf(nextList) || nextCell != currentCell))
            nextList = 0;
        // Place list item into adjoining lists.
        if (previousList)
            appendNode(listItemElement, previousList);
        else if (nextList)
            insertNodeAt(listItemElement, Position(nextList, 0));
        else {
            // Create the list.
            RefPtr<HTMLElement> listElement = m_type == OrderedList ? createOrderedListElement(document()) : createUnorderedListElement(document());
            m_listElement = listElement;
            appendNode(listItemElement, listElement);
            
            if (start == end && isBlock(start.deepEquivalent().node())) {
                // Inserting the list into an empty paragraph that isn't held open 
                // by a br or a '\n', will invalidate start and end.  Insert 
                // a placeholder and then recompute start and end.
                RefPtr<Node> placeholder = insertBlockPlaceholder(start.deepEquivalent());
                start = VisiblePosition(Position(placeholder.get(), 0));
                end = start;
            }
            
            // Insert the list at a position visually equivalent to start of the
            // paragraph that is being moved into the list. 
            // Try to avoid inserting it somewhere where it will be surrounded by 
            // inline ancestors of start, since it is easier for editing to produce 
            // clean markup when inline elements are pushed down as far as possible.
            Position insertionPos(start.deepEquivalent().upstream());
            // Also avoid the containing list item.
            Node* listChild = enclosingListChild(insertionPos.node());
            if (listChild && listChild->hasTagName(liTag))
                insertionPos = positionInParentBeforeNode(listChild);

            insertNodeAt(listElement, insertionPos);

            // We inserted the list at the start of the content we're about to move
            // Update the start of content, so we don't try to move the list into itself.  bug 19066
            if (insertionPos == start.deepEquivalent())
                start = startOfParagraph(originalStart);
        }
        moveParagraph(start, end, VisiblePosition(Position(placeholder.get(), 0)), true);
        if (nextList && previousList)
            mergeIdenticalElements(previousList, nextList);
    }
}