Exemplo n.º 1
0
bool Text::textLayoutObjectIsNeeded(const ComputedStyle& style, const LayoutObject& parent)
{
    if (!parent.canHaveChildren())
        return false;

    if (isEditingText())
        return true;

    if (!length())
        return false;

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

    if (!containsOnlyWhitespace())
        return true;

    if (!canHaveWhitespaceChildren(parent, this))
        return false;

    // pre-wrap in SVG never makes layoutObject.
    if (style.whiteSpace() == PRE_WRAP && parent.isSVG())
        return false;

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

    // childNeedsDistributionRecalc() here is rare, only happens JS calling surroundContents() etc. from DOMNodeInsertedIntoDocument etc.
    if (document().childNeedsDistributionRecalc())
        return true;

    const LayoutObject* prev = LayoutTreeBuilderTraversal::previousSiblingLayoutObject(*this);
    if (prev && prev->isBR()) // <span><br/> <br/></span>
        return false;

    if (parent.isLayoutInline()) {
        // <span><div/> <div/></span>
        if (prev && !prev->isInline() && !prev->isOutOfFlowPositioned())
            return false;
    } else {
        if (parent.isLayoutBlock() && !parent.childrenInline() && (!prev || !prev->isInline()))
            return false;

        // Avoiding creation of a layoutObject 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;

        LayoutObject* first = parent.slowFirstChild();
        while (first && first->isFloatingOrOutOfFlowPositioned() && maxSiblingsToVisit--)
            first = first->nextSibling();
        if (!first || first == layoutObject() || LayoutTreeBuilderTraversal::nextSiblingLayoutObject(*this) == first) {
            // Whitespace at the start of a block just goes away.  Don't even
            // make a layout object for this text.
            return false;
        }
    }
    return true;
}
Exemplo n.º 2
0
LayoutRubyText* LayoutRubyRun::rubyText() const
{
    LayoutObject* child = firstChild();
    // If in future it becomes necessary to support floating or positioned ruby text,
    // layout will have to be changed to handle them properly.
    ASSERT(!child || !child->isRubyText() || !child->isFloatingOrOutOfFlowPositioned());
    return child && child->isRubyText() ? static_cast<LayoutRubyText*>(child) : 0;
}
Exemplo n.º 3
0
LayoutBox* LayoutFieldset::findInFlowLegend() const {
  for (LayoutObject* legend = firstChild(); legend;
       legend = legend->nextSibling()) {
    if (legend->isFloatingOrOutOfFlowPositioned())
      continue;

    if (isHTMLLegendElement(legend->node()))
      return toLayoutBox(legend);
  }
  return nullptr;
}
Exemplo n.º 4
0
void LineBoxList::dirtyLinesFromChangedChild(LayoutObject* container, LayoutObject* child)
{
    if (!container->parent() || (container->isLayoutBlock() && (container->selfNeedsLayout() || !container->isLayoutBlockFlow())))
        return;

    LayoutInline* inlineContainer = container->isLayoutInline() ? toLayoutInline(container) : 0;
    InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox();

    // If we have no first line box, then just bail early.
    if (!firstBox) {
        // For an empty inline, go ahead and propagate the check up to our parent, unless the parent
        // is already dirty.
        if (container->isInline() && !container->ancestorLineBoxDirty()) {
            container->parent()->dirtyLinesFromChangedChild(container);
            container->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree.
        }
        return;
    }

    // Try to figure out which line box we belong in.  First try to find a previous
    // line box by examining our siblings.  If we didn't find a line box, then use our
    // parent's first line box.
    RootInlineBox* box = 0;
    LayoutObject* curr = 0;
    ListHashSet<LayoutObject*, 16> potentialLineBreakObjects;
    potentialLineBreakObjects.add(child);
    for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
        potentialLineBreakObjects.add(curr);

        if (curr->isFloatingOrOutOfFlowPositioned())
            continue;

        if (curr->isReplaced()) {
            InlineBox* wrapper = toLayoutBox(curr)->inlineBoxWrapper();
            if (wrapper)
                box = &wrapper->root();
        } else if (curr->isText()) {
            InlineTextBox* textBox = toLayoutText(curr)->lastTextBox();
            if (textBox)
                box = &textBox->root();
        } else if (curr->isLayoutInline()) {
            InlineBox* lastSiblingBox = toLayoutInline(curr)->lastLineBoxIncludingCulling();
            if (lastSiblingBox)
                box = &lastSiblingBox->root();
        }

        if (box)
            break;
    }
    if (!box) {
        if (inlineContainer && !inlineContainer->alwaysCreateLineBoxes()) {
            // https://bugs.webkit.org/show_bug.cgi?id=60778
            // We may have just removed a <br> with no line box that was our first child. In this case
            // we won't find a previous sibling, but firstBox can be pointing to a following sibling.
            // This isn't good enough, since we won't locate the root line box that encloses the removed
            // <br>. We have to just over-invalidate a bit and go up to our parent.
            if (!inlineContainer->ancestorLineBoxDirty()) {
                inlineContainer->parent()->dirtyLinesFromChangedChild(inlineContainer);
                inlineContainer->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree.
            }
            return;
        }
        box = &firstBox->root();
    }

    // If we found a line box, then dirty it.
    if (box) {
        RootInlineBox* adjacentBox;
        box->markDirty();

        // dirty the adjacent lines that might be affected
        // NOTE: we dirty the previous line because RootInlineBox objects cache
        // the address of the first object on the next line after a BR, which we may be
        // invalidating here.  For more info, see how LayoutBlock::layoutInlineChildren
        // calls setLineBreakInfo with the result of findNextLineBreak.  findNextLineBreak,
        // despite the name, actually returns the first LayoutObject after the BR.
        // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
        adjacentBox = box->prevRootBox();
        if (adjacentBox)
            adjacentBox->markDirty();
        adjacentBox = box->nextRootBox();
        // If |child| or any of its immediately previous siblings with culled lineboxes is the object after a line-break in |box| or the linebox after it
        // then that means |child| actually sits on the linebox after |box| (or is its line-break object) and so we need to dirty it as well.
        if (adjacentBox && (potentialLineBreakObjects.contains(box->lineBreakObj()) || potentialLineBreakObjects.contains(adjacentBox->lineBreakObj()) || child->isBR() || isIsolated(container->style()->unicodeBidi())))
            adjacentBox->markDirty();
    }
}
Exemplo n.º 5
0
LayoutObject* FirstLetterPseudoElement::firstLetterTextLayoutObject(const Element& element)
{
    LayoutObject* parentLayoutObject = 0;

    // If we are looking at a first letter element then we need to find the
    // first letter text layoutObject from the parent node, and not ourselves.
    if (element.isFirstLetterPseudoElement())
        parentLayoutObject = element.parentOrShadowHostElement()->layoutObject();
    else
        parentLayoutObject = element.layoutObject();

    if (!parentLayoutObject
        || !parentLayoutObject->style()->hasPseudoStyle(FIRST_LETTER)
        || !canHaveGeneratedChildren(*parentLayoutObject)
        || !(parentLayoutObject->isLayoutBlockFlow() || parentLayoutObject->isLayoutButton()))
        return nullptr;

    // Drill down into our children and look for our first text child.
    LayoutObject* firstLetterTextLayoutObject = parentLayoutObject->slowFirstChild();
    while (firstLetterTextLayoutObject) {
        // This can be called when the first letter layoutObject is already in the tree. We do not
        // want to consider that layoutObject for our text layoutObject so we go to the sibling (which is
        // the LayoutTextFragment for the remaining text).
        if (firstLetterTextLayoutObject->style() && firstLetterTextLayoutObject->style()->styleType() == FIRST_LETTER) {
            firstLetterTextLayoutObject = firstLetterTextLayoutObject->nextSibling();
        } else if (firstLetterTextLayoutObject->isText()) {
            // FIXME: If there is leading punctuation in a different LayoutText than
            // the first letter, we'll not apply the correct style to it.
            RefPtr<StringImpl> str = toLayoutText(firstLetterTextLayoutObject)->isTextFragment() ?
                toLayoutTextFragment(firstLetterTextLayoutObject)->completeText() :
                toLayoutText(firstLetterTextLayoutObject)->originalText();
            if (firstLetterLength(str.get()) || isInvalidFirstLetterLayoutObject(firstLetterTextLayoutObject))
                break;
            firstLetterTextLayoutObject = firstLetterTextLayoutObject->nextSibling();
        } else if (firstLetterTextLayoutObject->isListMarker()) {
            firstLetterTextLayoutObject = firstLetterTextLayoutObject->nextSibling();
        } else if (firstLetterTextLayoutObject->isFloatingOrOutOfFlowPositioned()) {
            if (firstLetterTextLayoutObject->style()->styleType() == FIRST_LETTER) {
                firstLetterTextLayoutObject = firstLetterTextLayoutObject->slowFirstChild();
                break;
            }
            firstLetterTextLayoutObject = firstLetterTextLayoutObject->nextSibling();
        } else if (firstLetterTextLayoutObject->isReplaced() || firstLetterTextLayoutObject->isLayoutButton()
            || firstLetterTextLayoutObject->isMenuList()) {
            return nullptr;
        } else if (firstLetterTextLayoutObject->isFlexibleBoxIncludingDeprecated() || firstLetterTextLayoutObject->isLayoutGrid()) {
            firstLetterTextLayoutObject = firstLetterTextLayoutObject->nextSibling();
        } else if (!firstLetterTextLayoutObject->isInline()
            && firstLetterTextLayoutObject->style()->hasPseudoStyle(FIRST_LETTER)
            && canHaveGeneratedChildren(*firstLetterTextLayoutObject)) {
            // There is a layoutObject further down the tree which has FIRST_LETTER set. When that node
            // is attached we will handle setting up the first letter then.
            return nullptr;
        } else {
            firstLetterTextLayoutObject = firstLetterTextLayoutObject->slowFirstChild();
        }
    }

    // No first letter text to display, we're done.
    // FIXME: This black-list of disallowed LayoutText subclasses is fragile. crbug.com/422336.
    // Should counter be on this list? What about LayoutTextFragment?
    if (!firstLetterTextLayoutObject || !firstLetterTextLayoutObject->isText() || isInvalidFirstLetterLayoutObject(firstLetterTextLayoutObject))
        return nullptr;

    return firstLetterTextLayoutObject;
}