Beispiel #1
0
DocumentFragment* createFragmentFromMarkupWithContext(
    Document& document,
    const String& markup,
    unsigned fragmentStart,
    unsigned fragmentEnd,
    const String& baseURL,
    ParserContentPolicy parserContentPolicy) {
  // FIXME: Need to handle the case where the markup already contains these
  // markers.

  StringBuilder taggedMarkup;
  taggedMarkup.append(markup.left(fragmentStart));
  MarkupFormatter::appendComment(taggedMarkup, fragmentMarkerTag);
  taggedMarkup.append(
      markup.substring(fragmentStart, fragmentEnd - fragmentStart));
  MarkupFormatter::appendComment(taggedMarkup, fragmentMarkerTag);
  taggedMarkup.append(markup.substring(fragmentEnd));

  DocumentFragment* taggedFragment = createFragmentFromMarkup(
      document, taggedMarkup.toString(), baseURL, parserContentPolicy);

  Comment* nodeBeforeContext = nullptr;
  Comment* nodeAfterContext = nullptr;
  if (!findNodesSurroundingContext(taggedFragment, nodeBeforeContext,
                                   nodeAfterContext))
    return nullptr;

  Document* taggedDocument = Document::create();
  taggedDocument->setContextFeatures(document.contextFeatures());

  Element* root = Element::create(QualifiedName::null(), taggedDocument);
  root->appendChild(taggedFragment);
  taggedDocument->appendChild(root);

  Range* range = Range::create(
      *taggedDocument,
      Position::afterNode(nodeBeforeContext).parentAnchoredEquivalent(),
      Position::beforeNode(nodeAfterContext).parentAnchoredEquivalent());

  Node* commonAncestor = range->commonAncestorContainer();
  HTMLElement* specialCommonAncestor =
      ancestorToRetainStructureAndAppearanceWithNoLayoutObject(commonAncestor);

  // When there's a special common ancestor outside of the fragment, we must
  // include it as well to preserve the structure and appearance of the
  // fragment. For example, if the fragment contains TD, we need to include the
  // enclosing TABLE tag as well.
  DocumentFragment* fragment = DocumentFragment::create(document);
  if (specialCommonAncestor)
    fragment->appendChild(specialCommonAncestor);
  else
    fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor));

  trimFragment(fragment, nodeBeforeContext, nodeAfterContext);

  return fragment;
}
Beispiel #2
0
JSValue* JSRange::getValueProperty(ExecState* exec, int token) const
{
    switch (token) {
    case StartContainerAttrNum: {
        ExceptionCode ec = 0;
        Range* imp = static_cast<Range*>(impl());

        KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->startContainer(ec)));
        setDOMException(exec, ec);
        return result;
    }
    case StartOffsetAttrNum: {
        ExceptionCode ec = 0;
        Range* imp = static_cast<Range*>(impl());

        KJS::JSValue* result = jsNumber(imp->startOffset(ec));
        setDOMException(exec, ec);
        return result;
    }
    case EndContainerAttrNum: {
        ExceptionCode ec = 0;
        Range* imp = static_cast<Range*>(impl());

        KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->endContainer(ec)));
        setDOMException(exec, ec);
        return result;
    }
    case EndOffsetAttrNum: {
        ExceptionCode ec = 0;
        Range* imp = static_cast<Range*>(impl());

        KJS::JSValue* result = jsNumber(imp->endOffset(ec));
        setDOMException(exec, ec);
        return result;
    }
    case CollapsedAttrNum: {
        ExceptionCode ec = 0;
        Range* imp = static_cast<Range*>(impl());

        KJS::JSValue* result = jsBoolean(imp->collapsed(ec));
        setDOMException(exec, ec);
        return result;
    }
    case CommonAncestorContainerAttrNum: {
        ExceptionCode ec = 0;
        Range* imp = static_cast<Range*>(impl());

        KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->commonAncestorContainer(ec)));
        setDOMException(exec, ec);
        return result;
    }
    case ConstructorAttrNum:
        return getConstructor(exec);
    }
    return 0;
}
Beispiel #3
0
// FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange? 
// FIXME: At least, annotation and style info should probably not be included in range.markupString()
static String createMarkupInternal(Document& document, const Range& range, const Range& updatedRange, Vector<Node*>* nodes,
    EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs)
{
    DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, (ASCIILiteral("<br class=\"" AppleInterchangeNewline "\">")));

    bool collapsed = updatedRange.collapsed(ASSERT_NO_EXCEPTION);
    if (collapsed)
        return emptyString();
    Node* commonAncestor = updatedRange.commonAncestorContainer(ASSERT_NO_EXCEPTION);
    if (!commonAncestor)
        return emptyString();

    document.updateLayoutIgnorePendingStylesheets();

    Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag);
    Node* fullySelectedRoot = 0;
    // FIXME: Do this for all fully selected blocks, not just the body.
    if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), &range))
        fullySelectedRoot = body;
    Node* specialCommonAncestor = highestAncestorToWrapMarkup(&updatedRange, shouldAnnotate);

    StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate, &updatedRange, specialCommonAncestor);
    Node* pastEnd = updatedRange.pastLastNode();

    Node* startNode = updatedRange.firstNode();
    VisiblePosition visibleStart(updatedRange.startPosition(), VP_DEFAULT_AFFINITY);
    VisiblePosition visibleEnd(updatedRange.endPosition(), VP_DEFAULT_AFFINITY);
    if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleStart)) {
        if (visibleStart == visibleEnd.previous())
            return interchangeNewlineString;

        accumulator.appendString(interchangeNewlineString);
        startNode = visibleStart.next().deepEquivalent().deprecatedNode();

        if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, ASSERT_NO_EXCEPTION) >= 0)
            return interchangeNewlineString;
    }

    Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd);

    if (specialCommonAncestor && lastClosed) {
        // Also include all of the ancestors of lastClosed up to this special ancestor.
        for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
            if (ancestor == fullySelectedRoot && !convertBlocksToInlines) {
                RefPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot);

                // Bring the background attribute over, but not as an attribute because a background attribute on a div
                // appears to have no effect.
                if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style() || !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundImage))
                    && toElement(fullySelectedRoot)->hasAttribute(backgroundAttr))
                    fullySelectedRootStyle->style()->setProperty(CSSPropertyBackgroundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr) + "')");

                if (fullySelectedRootStyle->style()) {
                    // Reset the CSS properties to avoid an assertion error in addStyleMarkup().
                    // This assertion is caused at least when we select all text of a <body> element whose
                    // 'text-decoration' property is "inherit", and copy it.
                    if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyTextDecoration))
                        fullySelectedRootStyle->style()->setProperty(CSSPropertyTextDecoration, CSSValueNone);
                    if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyWebkitTextDecorationsInEffect))
                        fullySelectedRootStyle->style()->setProperty(CSSPropertyWebkitTextDecorationsInEffect, CSSValueNone);
                    accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(), document, true);
                }
            } else {
                // Since this node and all the other ancestors are not in the selection we want to set RangeFullySelectsNode to DoesNotFullySelectNode
                // so that styles that affect the exterior of the node are not included.
                accumulator.wrapWithNode(*ancestor, convertBlocksToInlines, StyledMarkupAccumulator::DoesNotFullySelectNode);
            }
            if (nodes)
                nodes->append(ancestor);
            
            lastClosed = ancestor;
            
            if (ancestor == specialCommonAncestor)
                break;
        }
    }

    // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally.
    if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleEnd.previous()))
        accumulator.appendString(interchangeNewlineString);

    return accumulator.takeResults();
}