Ejemplo n.º 1
0
void RenderListItem::insertOrMoveMarkerRendererIfNeeded()
{
    // Sanity check the location of our marker.
    if (!m_marker)
        return;

    RenderElement* currentParent = m_marker->parent();
    RenderBlock* newParent = getParentOfFirstLineBox(this, m_marker);
    if (!newParent) {
        // If the marker is currently contained inside an anonymous box,
        // then we are the only item in that anonymous box (since no line box
        // parent was found). It's ok to just leave the marker where it is
        // in this case.
        if (currentParent && currentParent->isAnonymousBlock())
            return;
        newParent = this;
    }

    if (newParent != currentParent) {
        // Removing and adding the marker can trigger repainting in
        // containers other than ourselves, so we need to disable LayoutState.
        LayoutStateDisabler layoutStateDisabler(&view());
        m_marker->removeFromParent();
        newParent->addChild(m_marker, firstNonMarkerChild(newParent));
        m_marker->updateMarginsAndContent();
        // If current parent is an anonymous block that has lost all its children, destroy it.
        if (currentParent && currentParent->isAnonymousBlock() && !currentParent->firstChild() && !toRenderBlock(currentParent)->continuation())
            currentParent->destroy();
    }

}
Ejemplo n.º 2
0
void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild)
{
    // Note: The RenderMathMLBlock only allows element children to be added.
    Element* childElement = toElement(child->node());

    if (childElement && !childElement->previousElementSibling()) {
        // Position 1 is always the base of the msub/msup/msubsup.
        RenderBlock* baseWrapper = createAlmostAnonymousBlock(INLINE_BLOCK);
        RenderMathMLBlock::addChild(baseWrapper, firstChild());
        baseWrapper->addChild(child);
            
        // Make sure we have a script block for rendering.
        if (m_kind == SubSup && !m_scripts) {
            RefPtr<RenderStyle> scriptsStyle = RenderStyle::createAnonymousStyle(style());
            scriptsStyle->setDisplay(INLINE_BLOCK);
            scriptsStyle->setVerticalAlign(TOP);
            scriptsStyle->setMarginLeft(Length(gSubsupScriptMargin, Fixed));
            scriptsStyle->setTextAlign(LEFT);
            // Set this wrapper's font-size for its line-height & baseline position.
            scriptsStyle->setBlendedFontSize(static_cast<int>(0.75 * style()->fontSize()));
            m_scripts = new (renderArena()) RenderMathMLBlock(node());
            m_scripts->setStyle(scriptsStyle);
            RenderMathMLBlock::addChild(m_scripts, beforeChild);
        }
    } else {
        if (m_kind == SubSup) {
            ASSERT(childElement);
            if (!childElement)
                return;

            RenderBlock* script = m_scripts->createAlmostAnonymousBlock();

            // The order is always backwards so the first script is the subscript and the superscript 
            // is last. That means the superscript is the first to render vertically.
            Element* previousSibling = childElement->previousElementSibling();
            if (previousSibling && !previousSibling->previousElementSibling()) 
                m_scripts->addChild(script);
            else                 
                m_scripts->addChild(script, m_scripts->firstChild());
            
            script->addChild(child);
        } else
            RenderMathMLBlock::addChild(child, beforeChild);
    }
}
Ejemplo n.º 3
0
RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int lineHeight, int maxHeightForRenderer, int charRelative, int topRelative)
{
    RenderBlock* container = new (renderArena()) RenderMathMLBlock(node());
    container->setStyle(createStackableStyle(lineHeight, maxHeightForRenderer, topRelative));
    addChild(container);
    RenderBlock* parent = container;
    if (charRelative) {
        RenderBlock* charBlock = new (renderArena()) RenderBlock(node());
        RefPtr<RenderStyle> charStyle = RenderStyle::create();
        charStyle->inheritFrom(container->style());
        charStyle->setDisplay(INLINE_BLOCK);
        charStyle->setTop(Length(charRelative, Fixed));
        charStyle->setPosition(RelativePosition);
        charBlock->setStyle(charStyle);
        parent->addChild(charBlock);
        parent = charBlock;
    }
    
    RenderText* text = new (renderArena()) RenderText(node(), StringImpl::create(&glyph, 1));
    text->setStyle(container->style());
    parent->addChild(text);
    return container;
}
Ejemplo n.º 4
0
RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int maxHeightForRenderer, int charRelative)
{
    RenderBlock* container = new (renderArena()) RenderMathMLBlock(toElement(node()));
    toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);
    container->setStyle(createStackableStyle(maxHeightForRenderer));
    addChild(container);
    RenderBlock* parent = container;
    if (charRelative) {
        RenderBlock* charBlock = createAnonymous(document());
        RefPtr<RenderStyle> charStyle = RenderStyle::create();
        charStyle->inheritFrom(container->style());
        charStyle->setDisplay(INLINE_BLOCK);
        charStyle->setTop(Length(charRelative, Fixed));
        charStyle->setPosition(RelativePosition);
        charBlock->setStyle(charStyle);
        parent->addChild(charBlock);
        parent = charBlock;
    }

    RenderText* text = new (renderArena()) RenderText(node(), StringImpl::create(&glyph, 1));
    text->setStyle(container->style());
    parent->addChild(text);
    return container;
}
Ejemplo n.º 5
0
void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
{
    ASSERT(child);

    if (child->isRubyText()) {
        if (!beforeChild) {
            // RenderRuby has already ascertained that we can add the child here.
            ASSERT(!hasRubyText());
            // prepend ruby texts as first child
            RenderBlockFlow::addChild(child, firstChild());
        }  else if (beforeChild->isRubyText()) {
            // New text is inserted just before another.
            // In this case the new text takes the place of the old one, and
            // the old text goes into a new run that is inserted as next sibling.
            ASSERT(beforeChild->parent() == this);
            RenderObject* ruby = parent();
            ASSERT(ruby->isRuby());
            RenderBlock* newRun = staticCreateRubyRun(ruby);
            ruby->addChild(newRun, nextSibling());
            // Add the new ruby text and move the old one to the new run
            // Note: Doing it in this order and not using RenderRubyRun's methods,
            // in order to avoid automatic removal of the ruby run in case there is no
            // other child besides the old ruby text.
            RenderBlockFlow::addChild(child, beforeChild);
            RenderBlockFlow::removeChild(beforeChild);
            newRun->addChild(beforeChild);
        } else if (hasRubyBase()) {
            // Insertion before a ruby base object.
            // In this case we need insert a new run before the current one and split the base.
            RenderObject* ruby = parent();
            RenderRubyRun* newRun = staticCreateRubyRun(ruby);
            ruby->addChild(newRun, this);
            newRun->addChild(child);
            rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
        }
    } else {
        // child is not a text -> insert it into the base
        // (append it instead if beforeChild is the ruby text)
        RenderRubyBase* base = rubyBaseSafe();
        if (beforeChild == base)
            beforeChild = base->firstChild();
        if (beforeChild && beforeChild->isRubyText())
            beforeChild = 0;
        ASSERT(!beforeChild || beforeChild->isDescendantOf(base));
        base->addChild(child, beforeChild);
    }
}
Ejemplo n.º 6
0
void RenderMathMLRoot::addChild(RenderObject* child, RenderObject* )
{
    if (isEmpty()) {
        // Add a block for the index
        RenderBlock* indexWrapper = createAlmostAnonymousBlock(INLINE_BLOCK);
        RenderBlock::addChild(indexWrapper);
        
        // FIXME: the wrapping does not seem to be needed anymore.
        // this is the base, so wrap it so we can pad it
        RenderBlock* baseWrapper = createAlmostAnonymousBlock(INLINE_BLOCK);
        baseWrapper->style()->setPaddingLeft(Length(5 * gFrontWidthEms, Percent));
        RenderBlock::addChild(baseWrapper);
        baseWrapper->addChild(child);
    } else {
        // always add to the index
        firstChild()->addChild(child);
    }
}
Ejemplo n.º 7
0
void RenderListItem::insertOrMoveMarkerRendererIfNeeded()
{
    // Sanity check the location of our marker.
    if (!m_marker)
        return;

    // FIXME: Do not even try to reposition the marker when we are not in layout
    // until after we fixed webkit.org/b/163789.
    if (!view().frameView().isInRenderTreeLayout())
        return;

    RenderElement* currentParent = m_marker->parent();
    RenderBlock* newParent = getParentOfFirstLineBox(*this, *m_marker);
    if (!newParent) {
        // If the marker is currently contained inside an anonymous box,
        // then we are the only item in that anonymous box (since no line box
        // parent was found). It's ok to just leave the marker where it is
        // in this case.
        if (currentParent && currentParent->isAnonymousBlock())
            return;
        if (multiColumnFlowThread())
            newParent = multiColumnFlowThread();
        else
            newParent = this;
    }

    if (newParent != currentParent) {
        // Removing and adding the marker can trigger repainting in
        // containers other than ourselves, so we need to disable LayoutState.
        LayoutStateDisabler layoutStateDisabler(view());
        // Mark the parent dirty so that when the marker gets inserted into the tree
        // and dirties ancestors, it stops at the parent.
        newParent->setChildNeedsLayout(MarkOnlyThis);
        m_marker->setNeedsLayout(MarkOnlyThis);

        m_marker->removeFromParent();
        newParent->addChild(m_marker, firstNonMarkerChild(*newParent));
        m_marker->updateMarginsAndContent();
        // If current parent is an anonymous block that has lost all its children, destroy it.
        if (currentParent && currentParent->isAnonymousBlock() && !currentParent->firstChild() && !downcast<RenderBlock>(*currentParent).continuation())
            currentParent->destroy();
    }

}
Ejemplo n.º 8
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());
}
Ejemplo n.º 9
0
void RenderMathMLFraction::addChild(RenderObject* child, RenderObject* beforeChild)
{
    RenderBlock* row = new (renderArena()) RenderMathMLBlock(node());
    RefPtr<RenderStyle> rowStyle = makeBlockStyle();
    
    rowStyle->setTextAlign(CENTER);
    Length pad(static_cast<int>(rowStyle->fontSize() * gHorizontalPad), Fixed);
    rowStyle->setPaddingLeft(pad);
    rowStyle->setPaddingRight(pad);
    
    // Only add padding for rows as denominators
    bool isNumerator = isEmpty();
    if (!isNumerator) 
        rowStyle->setPaddingTop(Length(2, Fixed));
    
    row->setStyle(rowStyle.release());
    RenderBlock::addChild(row, beforeChild);
    row->addChild(child);
    updateFromElement();
}
void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild)
{
    if (firstChild()) {
        // We already have a base, so this is the super/subscripts being added.
        
        if (m_kind == SubSup) {
            if (!m_scripts) {
                m_scripts = new (renderArena()) RenderMathMLBlock(node());
                RefPtr<RenderStyle> scriptsStyle = RenderStyle::create();
                scriptsStyle->inheritFrom(style());
                scriptsStyle->setDisplay(INLINE_BLOCK);
                scriptsStyle->setVerticalAlign(MIDDLE);
                scriptsStyle->setMarginLeft(Length(gSubsupScriptMargin, Fixed));
                scriptsStyle->setTextAlign(LEFT);
                m_scripts->setStyle(scriptsStyle.release());
                RenderMathMLBlock::addChild(m_scripts, beforeChild);
            }
            
            RenderBlock* script = new (renderArena()) RenderMathMLBlock(node());
            RefPtr<RenderStyle> scriptStyle = RenderStyle::create();
            scriptStyle->inheritFrom(m_scripts->style());
            scriptStyle->setDisplay(BLOCK);
            script->setStyle(scriptStyle.release());
            
            m_scripts->addChild(script, m_scripts->firstChild());
            script->addChild(child);
        } else
            RenderMathMLBlock::addChild(child, beforeChild);
        
    } else {
        RenderMathMLBlock* wrapper = new (renderArena()) RenderMathMLBlock(node());
        RefPtr<RenderStyle> wrapperStyle = RenderStyle::create();
        wrapperStyle->inheritFrom(style());
        wrapperStyle->setDisplay(INLINE_BLOCK);
        wrapperStyle->setVerticalAlign(MIDDLE);
        wrapper->setStyle(wrapperStyle.release());
        RenderMathMLBlock::addChild(wrapper, beforeChild);
        wrapper->addChild(child);
    }
}
void RenderMathMLRoot::addChild(RenderObject* child, RenderObject* )
{
    if (isEmpty()) {
        // Add a block for the index
        RenderBlock* block = new (renderArena()) RenderBlock(node());
        RefPtr<RenderStyle> indexStyle = makeBlockStyle();
        indexStyle->setDisplay(INLINE_BLOCK);
        block->setStyle(indexStyle.release());
        RenderBlock::addChild(block);
        
        // FIXME: the wrapping does not seem to be needed anymore.
        // this is the base, so wrap it so we can pad it
        block = new (renderArena()) RenderBlock(node());
        RefPtr<RenderStyle> baseStyle = makeBlockStyle();
        baseStyle->setDisplay(INLINE_BLOCK);
        baseStyle->setPaddingLeft(Length(5 * gRadicalWidth , Percent));
        block->setStyle(baseStyle.release());
        RenderBlock::addChild(block);
        block->addChild(child);
    } else {
        // always add to the index
        firstChild()->addChild(child);
    }
}
Ejemplo n.º 12
0
// FIXME: It's cleaner to only call updateFromElement when an attribute has changed. The body of
// this method should probably be moved to a private stretchHeightChanged or checkStretchHeight
// method. Probably at the same time, addChild/removeChild methods should be made to work for
// dynamic DOM changes.
void RenderMathMLOperator::updateFromElement()
{
    RenderObject* savedRenderer = node()->renderer();

    // Destroy our current children
    children()->destroyLeftoverChildren();

    // Since we share a node with our children, destroying our children may set our node's
    // renderer to 0, so we need to restore it.
    node()->setRenderer(savedRenderer);
    
    // If the operator is fixed, it will be contained in m_operator
    UChar firstChar = m_operator;
    
    // This boolean indicates whether stretching is disabled via the markup.
    bool stretchDisabled = false;
    
    // We may need the element later if we can't stretch.
    if (node()->nodeType() == Node::ELEMENT_NODE) {
        if (Element* mo = static_cast<Element*>(node())) {
            AtomicString stretchyAttr = mo->getAttribute(MathMLNames::stretchyAttr);
            stretchDisabled = equalIgnoringCase(stretchyAttr, "false");
            
            // If stretching isn't disabled, get the character from the text content.
            if (!stretchDisabled && !firstChar) {
                String opText = mo->textContent();
                for (unsigned int i = 0; !firstChar && i < opText.length(); i++) {
                    if (!isSpaceOrNewline(opText[i]))
                        firstChar = opText[i];
                }
            }
        }
    }
    
    // The 'index' holds the stretchable character's glyph information
    int index = -1;
    
    // isStretchy indicates whether the character is streatchable via a number of factors.
    bool isStretchy = false;
    
    // Check for a stretchable character.
    if (!stretchDisabled && firstChar) {
        const int maxIndex = WTF_ARRAY_LENGTH(stretchyCharacters);
        for (index++; index < maxIndex; index++) {
            if (stretchyCharacters[index].character == firstChar) {
                isStretchy = true;
                break;
            }
        }
    }
    
    // We only stretch character if the stretch height is larger than a minimum size (e.g. 24px).
    bool shouldStretch = isStretchy && m_stretchHeight>gMinimumStretchHeight;
    
    // Either stretch is disabled or we don't have a stretchable character over the minimum height
    if (stretchDisabled || !shouldStretch) {
        m_isStacked = false;
        RenderBlock* container = new (renderArena()) RenderMathMLBlock(node());
        
        RefPtr<RenderStyle> newStyle = RenderStyle::create();
        newStyle->inheritFrom(style());
        newStyle->setDisplay(INLINE_BLOCK);
        newStyle->setVerticalAlign(BASELINE);
        
        // Check for a stretchable character that is under the minimum height and use the
        // font size to adjust the glyph size.
        int currentFontSize = style()->fontSize();
        if (!stretchDisabled && isStretchy && m_stretchHeight > 0 && m_stretchHeight <= gMinimumStretchHeight  && m_stretchHeight > currentFontSize) {
            FontDescription desc = style()->fontDescription();
            desc.setIsAbsoluteSize(true);
            desc.setSpecifiedSize(m_stretchHeight);
            desc.setComputedSize(m_stretchHeight);
            newStyle->setFontDescription(desc);
            newStyle->font().update(style()->font().fontSelector());
        }

        container->setStyle(newStyle.release());
        addChild(container);
        
        // Build the text of the operator.
        RenderText* text = 0;
        if (m_operator) 
            text = new (renderArena()) RenderText(node(), StringImpl::create(&m_operator, 1));
        else if (node()->nodeType() == Node::ELEMENT_NODE)
            if (Element* mo = static_cast<Element*>(node()))
                text = new (renderArena()) RenderText(node(), mo->textContent().replace(hyphenMinus, minusSign).impl());
        // If we can't figure out the text, leave it blank.
        if (text) {
            RefPtr<RenderStyle> textStyle = RenderStyle::create();
            textStyle->inheritFrom(container->style());
            text->setStyle(textStyle.release());
            container->addChild(text);
        }
    } else {
        // Build stretchable characters as a stack of glyphs.
        m_isStacked = true;
    
        int extensionGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].extensionGlyph);
        int topGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].topGlyph);
        int bottomGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].bottomGlyph);
        
        if (stretchyCharacters[index].middleGlyph) {
            // We have a middle glyph (e.g. a curly bracket) that requires special processing.
            int glyphHeight = glyphHeightForCharacter(stretchyCharacters[index].middleGlyph);
            int middleGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].middleGlyph);
            int half = (m_stretchHeight - glyphHeight) / 2;
            if (half <= glyphHeight) {
                // We only have enough space for a single middle glyph.
                createGlyph(stretchyCharacters[index].topGlyph, topGlyphLineHeight, half, gTopGlyphTopAdjust);
                createGlyph(stretchyCharacters[index].middleGlyph, middleGlyphLineHeight, glyphHeight, gMiddleGlyphTopAdjust);
                createGlyph(stretchyCharacters[index].bottomGlyph, bottomGlyphLineHeight, 0, gBottomGlyphTopAdjust);
            } else {
                // We have to extend both the top and bottom to the middle.
                createGlyph(stretchyCharacters[index].topGlyph, topGlyphLineHeight, glyphHeight, gTopGlyphTopAdjust);
                int remaining = half - glyphHeight;
                while (remaining > 0) {
                    if (remaining < glyphHeight) {
                        createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, remaining);
                        remaining = 0;
                    } else {
                        createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, glyphHeight);
                        remaining -= glyphHeight;
                    }
                }
                
                // The middle glyph in the stack.
                createGlyph(stretchyCharacters[index].middleGlyph, middleGlyphLineHeight, glyphHeight, gMiddleGlyphTopAdjust);
                
                // The remaining is the top half minus the middle glyph height.
                remaining = half - glyphHeight;
                // We need to make sure we have the full height in case the height is odd.
                if (m_stretchHeight % 2 == 1)
                    remaining++;
                
                // Extend to the bottom glyph.
                while (remaining > 0) {
                    if (remaining < glyphHeight) {
                        createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, remaining);
                        remaining = 0;
                    } else {
                        createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, glyphHeight);
                        remaining -= glyphHeight;
                    }
                }
                
                // The bottom glyph in the stack.
                createGlyph(stretchyCharacters[index].bottomGlyph, bottomGlyphLineHeight, 0, gBottomGlyphTopAdjust);
            }
        } else {
            // We do not have a middle glyph and so we just extend from the top to the bottom glyph.
            int glyphHeight = glyphHeightForCharacter(stretchyCharacters[index].extensionGlyph);
            int remaining = m_stretchHeight - 2 * glyphHeight;
            createGlyph(stretchyCharacters[index].topGlyph, topGlyphLineHeight, glyphHeight, gTopGlyphTopAdjust);
            while (remaining > 0) {
                if (remaining < glyphHeight) {
                    createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, remaining);
                    remaining = 0;
                } else {
                    createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, glyphHeight);
                    remaining -= glyphHeight;
                }
            }
            createGlyph(stretchyCharacters[index].bottomGlyph, bottomGlyphLineHeight, 0, gBottomGlyphTopAdjust);
        }
    }
    
    setNeedsLayoutAndPrefWidthsRecalc();
}
Ejemplo n.º 13
0
void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
{
    // Insert :before and :after content before/after the RenderRubyRun(s)
    if (child->isBeforeContent()) {
        if (child->isInline()) {
            // Add generated inline content normally
            RenderBlock::addChild(child, firstChild());
        } else {
            // Wrap non-inline content with an anonymous inline-block.
            RenderBlock* beforeBlock = rubyBeforeBlock(this);
            if (!beforeBlock) {
                beforeBlock = createAnonymousRubyInlineBlock(this);
                RenderBlock::addChild(beforeBlock, firstChild());
            }
            beforeBlock->addChild(child);
        }
        return;
    }
    if (child->isAfterContent()) {
        if (child->isInline()) {
            // Add generated inline content normally
            RenderBlock::addChild(child);
        } else {
            // Wrap non-inline content with an anonymous inline-block.
            RenderBlock* afterBlock = rubyAfterBlock(this);
            if (!afterBlock) {
                afterBlock = createAnonymousRubyInlineBlock(this);
                RenderBlock::addChild(afterBlock);
            }
            afterBlock->addChild(child);
        }
        return;
    }

    // If the child is a ruby run, just add it normally.
    if (child->isRubyRun()) {
        RenderBlock::addChild(child, beforeChild);
        return;
    }

    if (beforeChild && !isAfterContent(beforeChild)) {
        // insert child into run
        ASSERT(!beforeChild->isRubyRun());
        RenderObject* run = beforeChild;
        while (run && !run->isRubyRun())
            run = run->parent();
        if (run) {
            run->addChild(child, beforeChild);
            return;
        }
        ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent!
        // Emergency fallback: fall through and just append.
    }

    // If the new child would be appended, try to add the child to the previous run
    // if possible, or create a new run otherwise.
    // (The RenderRubyRun object will handle the details)
    RenderRubyRun* lastRun = lastRubyRun(this);
    if (!lastRun || lastRun->hasRubyText()) {
        lastRun = RenderRubyRun::staticCreateRubyRun(this);
        RenderBlock::addChild(lastRun, beforeChild);
    }
    lastRun->addChild(child);
}
Ejemplo n.º 14
0
// FIXME: It's cleaner to only call updateFromElement when an attribute has changed. The body of
// this method should probably be moved to a private stretchHeightChanged or checkStretchHeight
// method. Probably at the same time, addChild/removeChild methods should be made to work for
// dynamic DOM changes.
void RenderMathMLOperator::updateFromElement()
{
    RenderObject* savedRenderer = node()->renderer();

    // Destroy our current children
    children()->destroyLeftoverChildren();

    // Since we share a node with our children, destroying our children may set our node's
    // renderer to 0, so we need to restore it.
    node()->setRenderer(savedRenderer);

    int index = stretchyCharacterIndex();
    bool isStretchy = index >= 0;

    // We only stack glyphs if the stretch height is larger than a minimum size.
    bool shouldStack = isStretchy && m_stretchHeight > style()->fontSize();

    struct StretchyCharacter* partsData = 0;
    float topGlyphHeight = 0;
    float extensionGlyphHeight = 0;
    float bottomGlyphHeight = 0;
    float middleGlyphHeight = 0;
    if (isStretchy) {
        partsData = &stretchyCharacters[index];

        FontCachePurgePreventer fontCachePurgePreventer;

        topGlyphHeight = glyphHeightForCharacter(partsData->topGlyph);
        extensionGlyphHeight = glyphHeightForCharacter(partsData->extensionGlyph) - 1;
        bottomGlyphHeight = glyphHeightForCharacter(partsData->bottomGlyph);
        if (partsData->middleGlyph)
            middleGlyphHeight = glyphHeightForCharacter(partsData->middleGlyph) - 1;
        shouldStack = m_stretchHeight >= topGlyphHeight + middleGlyphHeight + bottomGlyphHeight && extensionGlyphHeight > 0;
    }

    bool stretchDisabled = stretchDisabledByMarkup();
    // Either stretch is disabled or we don't have a stretchable character over the minimum height
    if (stretchDisabled || !shouldStack) {
        RenderBlock* container = new (renderArena()) RenderMathMLBlock(toElement(node()));
        toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);

        RefPtr<RenderStyle> newStyle = RenderStyle::create();
        newStyle->inheritFrom(style());
        newStyle->setDisplay(FLEX);
        newStyle->setJustifyContent(JustifyCenter);

        UChar firstCharacter = firstTextCharacter();
        m_isStretched = firstCharacter && isStretchy && m_stretchHeight > style()->fontMetrics().floatHeight();
        if (m_isStretched)
            newStyle->setHeight(Length(m_stretchHeight, Fixed));
        container->setStyle(newStyle.release());
        addChild(container);

        if (m_isStretched) {
            float scaleY = m_stretchHeight / glyphHeightForCharacter(firstCharacter);
            TransformOperations transform;
            transform.operations().append(ScaleTransformOperation::create(1.0, scaleY, ScaleTransformOperation::SCALE_X));

            RefPtr<RenderStyle> innerStyle = RenderStyle::create();
            innerStyle->inheritFrom(style());
            innerStyle->setTransform(transform);
            innerStyle->setTransformOriginY(Length(0, Fixed));

            RenderBlock* innerContainer = new (renderArena()) RenderMathMLBlock(toElement(node()));
            toRenderMathMLBlock(innerContainer)->setIgnoreInAccessibilityTree(true);
            innerContainer->setStyle(innerStyle);
            container->addChild(innerContainer);

            container = innerContainer;
        }

        // Build the text of the operator.
        RenderText* text = 0;
        if (m_operator)
            text = new (renderArena()) RenderText(node(), StringImpl::create(&m_operator, 1));
        else if (node()->isElementNode())
            if (Element* mo = static_cast<Element*>(node()))
                text = new (renderArena()) RenderText(node(), mo->textContent().replace(hyphenMinus, minusSign).impl());
        // If we can't figure out the text, leave it blank.
        if (text) {
            RefPtr<RenderStyle> textStyle = RenderStyle::create();
            textStyle->inheritFrom(container->style());
            text->setStyle(textStyle.release());
            container->addChild(text);
        }
    } else {
        // Build stretchable characters as a stack of glyphs.
        m_isStretched = true;

        // To avoid gaps, we position glyphs after the top glyph upward by 1px. We also truncate
        // glyph heights to ints, and then reduce all but the top & bottom such heights by 1px.

        int remaining = m_stretchHeight - topGlyphHeight - bottomGlyphHeight;
        createGlyph(partsData->topGlyph, topGlyphHeight, 0);
        if (partsData->middleGlyph) {
            // We have a middle glyph (e.g. a curly bracket) that requires special processing.
            remaining -= middleGlyphHeight;
            int half = (remaining + 1) / 2;
            remaining -= half;
            while (remaining > 0) {
                int height = std::min<int>(remaining, extensionGlyphHeight);
                createGlyph(partsData->extensionGlyph, height, -1);
                remaining -= height;
            }

            // The middle glyph in the stack.
            createGlyph(partsData->middleGlyph, middleGlyphHeight, -1);

            remaining = half;
            while (remaining > 0) {
                int height = std::min<int>(remaining, extensionGlyphHeight);
                createGlyph(partsData->extensionGlyph, height, -1);
                remaining -= height;
            }
        } else {
            // We do not have a middle glyph and so we just extend from the top to the bottom glyph.
            while (remaining > 0) {
                int height = std::min<int>(remaining, extensionGlyphHeight);
                createGlyph(partsData->extensionGlyph, height, -1);
                remaining -= height;
            }
        }
        createGlyph(partsData->bottomGlyph, bottomGlyphHeight, -1);
    }

    setNeedsLayoutAndPrefWidthsRecalc();
}
// FIXME: It's cleaner to only call updateFromElement when an attribute has changed. The body of
// this method should probably be moved to a private stretchHeightChanged or checkStretchHeight
// method. Probably at the same time, addChild/removeChild methods should be made to work for
// dynamic DOM changes.
void RenderMathMLOperator::updateFromElement()
{
    RenderObject* savedRenderer = node()->renderer();

    // Destroy our current children
    children()->destroyLeftoverChildren();

    // Since we share a node with our children, destroying our children may set our node's
    // renderer to 0, so we need to restore it.
    node()->setRenderer(savedRenderer);
    
    // If the operator is fixed, it will be contained in m_operator
    UChar firstChar = m_operator;
    
    // This boolean indicates whether stretching is disabled via the markup.
    bool stretchDisabled = false;
    
    // We may need the element later if we can't stretch.
    if (node()->isElementNode()) {
        if (Element* mo = toElement(node())) {
            AtomicString stretchyAttr = mo->getAttribute(MathMLNames::stretchyAttr);
            stretchDisabled = equalIgnoringCase(stretchyAttr, "false");
            
            // If stretching isn't disabled, get the character from the text content.
            if (!stretchDisabled && !firstChar) {
                String opText = mo->textContent();
                for (unsigned int i = 0; !firstChar && i < opText.length(); i++) {
                    if (!isSpaceOrNewline(opText[i]))
                        firstChar = opText[i];
                }
            }
        }
    }
    
    // The 'index' holds the stretchable character's glyph information
    int index = -1;
    
    // isStretchy indicates whether the character is streatchable via a number of factors.
    bool isStretchy = false;
    
    // Check for a stretchable character.
    if (!stretchDisabled && firstChar) {
        const int maxIndex = WTF_ARRAY_LENGTH(stretchyCharacters);
        for (index++; index < maxIndex; index++) {
            if (stretchyCharacters[index].character == firstChar) {
                isStretchy = true;
                break;
            }
        }
    }
    
    // We only stack glyphs if the stretch height is larger than a minimum size.
    bool shouldStack = isStretchy && m_stretchHeight > style()->fontSize();
    struct StretchyCharacter* partsData = 0;
    int topGlyphHeight = 0;
    int extensionGlyphHeight = 0;
    int bottomGlyphHeight = 0;
    int middleGlyphHeight = 0;
    if (shouldStack) {
        partsData = &stretchyCharacters[index];
        
        FontCachePurgePreventer fontCachePurgePreventer;
        
        topGlyphHeight = glyphHeightForCharacter(partsData->topGlyph);
        extensionGlyphHeight = glyphHeightForCharacter(partsData->extensionGlyph) - 1;
        bottomGlyphHeight = glyphHeightForCharacter(partsData->bottomGlyph);
        if (partsData->middleGlyph)
            middleGlyphHeight = glyphHeightForCharacter(partsData->middleGlyph) - 1;
        shouldStack = m_stretchHeight >= topGlyphHeight + middleGlyphHeight + bottomGlyphHeight && extensionGlyphHeight > 0;
    }
    
    // Either stretch is disabled or we don't have a stretchable character over the minimum height
    if (stretchDisabled || !shouldStack) {
        m_isStacked = false;
        RenderBlock* container = new (renderArena()) RenderMathMLBlock(toElement(node()));
        // This container doesn't offer any useful information to accessibility.
        toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);
        
        RefPtr<RenderStyle> newStyle = RenderStyle::create();
        newStyle->inheritFrom(style());
        newStyle->setDisplay(FLEX);
        
        // Check for a stretchable character that is under the minimum height.
        if (!stretchDisabled && isStretchy && m_stretchHeight > style()->fontSize()) {
            FontDescription desc = style()->fontDescription();
            desc.setIsAbsoluteSize(true);
            desc.setSpecifiedSize(m_stretchHeight);
            desc.setComputedSize(m_stretchHeight);
            newStyle->setFontDescription(desc);
            newStyle->font().update(style()->font().fontSelector());
        }

        container->setStyle(newStyle.release());
        addChild(container);
        
        // Build the text of the operator.
        RenderText* text = 0;
        if (m_operator) 
            text = new (renderArena()) RenderText(node(), StringImpl::create(&m_operator, 1));
        else if (node()->isElementNode())
            if (Element* mo = toElement(node()))
                text = new (renderArena()) RenderText(node(), mo->textContent().replace(hyphenMinus, minusSign).impl());
        // If we can't figure out the text, leave it blank.
        if (text) {
            RefPtr<RenderStyle> textStyle = RenderStyle::create();
            textStyle->inheritFrom(container->style());
            text->setStyle(textStyle.release());
            container->addChild(text);
        }
    } else {
        // Build stretchable characters as a stack of glyphs.
        m_isStacked = true;
    
        // To avoid gaps, we position glyphs after the top glyph upward by 1px. We also truncate
        // glyph heights to ints, and then reduce all but the top & bottom such heights by 1px.
        
        int remaining = m_stretchHeight - topGlyphHeight - bottomGlyphHeight;
        createGlyph(partsData->topGlyph, topGlyphHeight, 0);
        if (partsData->middleGlyph) {
            // We have a middle glyph (e.g. a curly bracket) that requires special processing.
            remaining -= middleGlyphHeight;
            int half = (remaining + 1) / 2;
            remaining -= half;
                while (remaining > 0) {
                int height = std::min<int>(remaining, extensionGlyphHeight);
                createGlyph(partsData->extensionGlyph, height, -1);
                remaining -= height;
                }
                
                // The middle glyph in the stack.
            createGlyph(partsData->middleGlyph, middleGlyphHeight, -1);
                
            remaining = half;
                while (remaining > 0) {
                int height = std::min<int>(remaining, extensionGlyphHeight);
                createGlyph(partsData->extensionGlyph, height, -1);
                remaining -= height;
            }
        } else {
            // We do not have a middle glyph and so we just extend from the top to the bottom glyph.
            while (remaining > 0) {
                int height = std::min<int>(remaining, extensionGlyphHeight);
                createGlyph(partsData->extensionGlyph, height, -1);
                remaining -= height;
                }
            }
        createGlyph(partsData->bottomGlyph, bottomGlyphHeight, -1);
    }
    
    setNeedsLayoutAndPrefWidthsRecalc();
}