void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child, bool adding)
{
    if (!parent() || selfNeedsLayout() || isTable())
        return;

    // For an empty inline, go ahead and propagate the check up to our parent.
    if (isInline() && !firstLineBox())
        return parent()->dirtyLinesFromChangedChild(this);
    
    // 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;
    RenderObject* curr = 0;
    for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
        if (curr->isFloatingOrPositioned())
            continue;
        
        if (curr->isReplaced()) {
            InlineBox* wrapper = curr->inlineBoxWrapper();
            if (wrapper)
                box = wrapper->root();
        }
        else if (curr->isText()) {
            InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox();
            if (textBox)
                box = textBox->root();
        }
        else if (curr->isInlineFlow()) {
            InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox();
            if (runBox)
                box = runBox->root();
        }
        
        if (box)
            break;
    }
    if (!box && firstLineBox())
        box = firstLineBox()->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 RenderBlock::layoutInlineChildren
        // calls setLineBreakInfo with the result of findNextLineBreak.  findNextLineBreak,
        // despite the name, actually returns the first RenderObject after the BR.
        // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
        adjacentBox = box->prevRootBox();
        if (adjacentBox)
            adjacentBox->markDirty();
        if (child->isBR() || (curr && curr->isBR())) {
            adjacentBox = box->nextRootBox();
            if (adjacentBox)
                adjacentBox->markDirty();
        }
    }
}
示例#2
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();
    }
}
示例#3
0
void RootInlineBox::childRemoved(InlineBox* box)
{
    if (box->renderer() == m_lineBreakObj)
        setLineBreakInfo(0, 0, BidiStatus());

    for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->renderer(); prev = prev->prevRootBox()) {
        prev->setLineBreakInfo(0, 0, BidiStatus());
        prev->markDirty();
    }
}
示例#4
0
void RenderLineBoxList::dirtyLinesFromChangedChild(RenderBoxModelObject& container, RenderObject& child)
{
    ASSERT(is<RenderInline>(container) || is<RenderBlockFlow>(container));
    if (!container.parent() || (is<RenderBlockFlow>(container) && container.selfNeedsLayout()))
        return;

    RenderInline* inlineContainer = is<RenderInline>(container) ? &downcast<RenderInline>(container) : nullptr;
    InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox();

    // If we have no first line box, then just bail early.
    if (!firstBox) {
        // For an empty inline, 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 = nullptr;
    RenderObject* current;
    for (current = child.previousSibling(); current; current = current->previousSibling()) {
        if (current->isFloatingOrOutOfFlowPositioned())
            continue;

        if (current->isReplaced()) {
            if (auto wrapper = downcast<RenderBox>(*current).inlineBoxWrapper())
                box = &wrapper->root();
        } if (is<RenderLineBreak>(*current)) {
            if (auto wrapper = downcast<RenderLineBreak>(*current).inlineBoxWrapper())
                box = &wrapper->root();
        } else if (is<RenderText>(*current)) {
            if (InlineTextBox* textBox = downcast<RenderText>(*current).lastTextBox())
                box = &textBox->root();
        } else if (is<RenderInline>(*current)) {
            InlineBox* lastSiblingBox = downcast<RenderInline>(*current).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) {
        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 RenderBlock::layoutInlineChildren
        // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak,
        // despite the name, actually returns the first RenderObject after the BR.
        // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
        if (RootInlineBox* prevBox = box->prevRootBox())
            prevBox->markDirty();

        // FIXME: We shouldn't need to always dirty the next line. This is only strictly 
        // necessary some of the time, in situations involving BRs.
        if (RootInlineBox* nextBox = box->nextRootBox()) {
            nextBox->markDirty();
            // Dedicated linebox for floats may be added as the last rootbox. If this occurs with BRs inside inlines that propagte their lineboxes to
            // the parent flow, we need to invalidate it explicitly.
            // FIXME: We should be able to figure out the actual "changed child" even when we are calling through empty inlines recursively.
            if (is<RenderInline>(child) && !downcast<RenderInline>(child).firstLineBoxIncludingCulling()) {
                auto* lastRootBox = nextBox->blockFlow().lastRootBox();
                if (lastRootBox->isTrailingFloatsRootInlineBox() && !lastRootBox->isDirty())
                    lastRootBox->markDirty();
            }
        }
    }
}
示例#5
0
bool RenderTextLineBoxes::dirtyRange(RenderText& renderer, unsigned start, unsigned end, int lengthDelta)
{
    RootInlineBox* firstRootBox = nullptr;
    RootInlineBox* lastRootBox = nullptr;

    // Dirty all text boxes that include characters in between offset and offset+len.
    bool dirtiedLines = false;
    for (auto current = m_first; current; current = current->nextTextBox()) {
        // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
        // Text run is entirely before the affected range.
        if (current->end() < start)
            continue;
        // Text run is entirely after the affected range.
        if (current->start() > end) {
            current->offsetRun(lengthDelta);
            auto& rootBox = current->root();
            if (!firstRootBox) {
                firstRootBox = &rootBox;
                if (!dirtiedLines) {
                    // The affected area was in between two runs. Go ahead and mark the root box of
                    // the run after the affected area as dirty.
                    firstRootBox->markDirty();
                    dirtiedLines = true;
                }
            }
            lastRootBox = &rootBox;
            continue;
        }
        if (current->end() >= start && current->end() <= end) {
            // Text run overlaps with the left end of the affected range.
            current->dirtyLineBoxes();
            dirtiedLines = true;
            continue;
        }
        if (current->start() <= start && current->end() >= end) {
            // Text run subsumes the affected range.
            current->dirtyLineBoxes();
            dirtiedLines = true;
            continue;
        }
        if (current->start() <= end && current->end() >= end) {
            // Text run overlaps with right end of the affected range.
            current->dirtyLineBoxes();
            dirtiedLines = true;
            continue;
        }
    }

    // Now we have to walk all of the clean lines and adjust their cached line break information
    // to reflect our updated offsets.
    if (lastRootBox)
        lastRootBox = lastRootBox->nextRootBox();
    if (firstRootBox) {
        auto previousRootBox = firstRootBox->prevRootBox();
        if (previousRootBox)
            firstRootBox = previousRootBox;
    } else if (m_last) {
        ASSERT(!lastRootBox);
        firstRootBox = &m_last->root();
        firstRootBox->markDirty();
        dirtiedLines = true;
    }
    for (auto current = firstRootBox; current && current != lastRootBox; current = current->nextRootBox()) {
        if (current->lineBreakObj() == &renderer && current->lineBreakPos() > end)
            current->setLineBreakPos(current->lineBreakPos() + lengthDelta);
    }
    
    // If the text node is empty, dirty the line where new text will be inserted.
    if (!m_first && renderer.parent()) {
        renderer.parent()->dirtyLinesFromChangedChild(&renderer);
        dirtiedLines = true;
    }
    return dirtiedLines;
}
示例#6
0
void RootInlineBox::childRemoved(InlineBox* box)
{
    if (box->object() == m_lineBreakObj)
        setLineBreakInfo(0, 0, 0, 0);

    for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->object(); prev = prev->prevRootBox()) {
        prev->setLineBreakInfo(0, 0, 0, 0);
        prev->markDirty();
    }
}
void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, RenderObject* child)
{
    if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isBlockFlow())))
        return;

    RenderInline* inlineContainer = container->isRenderInline() ? toRenderInline(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;
    RenderObject* curr = 0;
    for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
        if (curr->isFloatingOrOutOfFlowPositioned())
            continue;

        if (curr->isReplaced()) {
            InlineBox* wrapper = toRenderBox(curr)->inlineBoxWrapper();
            if (wrapper)
                box = wrapper->root();
        } else if (curr->isText()) {
            InlineTextBox* textBox = toRenderText(curr)->lastTextBox();
            if (textBox)
                box = textBox->root();
        } else if (curr->isRenderInline()) {
            InlineBox* lastSiblingBox = toRenderInline(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 RenderBlock::layoutInlineChildren
        // calls setLineBreakInfo with the result of findNextLineBreak.  findNextLineBreak,
        // despite the name, actually returns the first RenderObject 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| has been inserted before the first element in the linebox, but after collapsed leading
        // space, the search for |child|'s linebox will go past the leading space to the previous linebox and select that
        // one as |box|. If we hit that situation here, dirty the |box| actually containing the child too. 
        bool insertedAfterLeadingSpace = box->lineBreakObj() == child->previousSibling();
        if (adjacentBox && (adjacentBox->lineBreakObj() == child || child->isBR() || (curr && curr->isBR()) || insertedAfterLeadingSpace))
            adjacentBox->markDirty();
    }
}