PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderElement& renderer) { if (!renderer.isCSSAnimating()) return &renderer.style(); return m_data->getAnimatedStyleForRenderer(renderer); }
void RenderSVGResourceFilter::postApplyResource(RenderElement& renderer, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*) { ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); FilterData* filterData = m_filter.get(&renderer); if (!filterData) return; switch (filterData->state) { case FilterData::MarkedForRemoval: m_filter.remove(&renderer); return; case FilterData::CycleDetected: case FilterData::Applying: // We have a cycle if we are already applying the data. // This can occur due to FeImage referencing a source that makes use of the FEImage itself. // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack // will continue correctly. filterData->state = FilterData::PaintingSource; return; case FilterData::PaintingSource: if (!filterData->savedContext) { removeClientFromCache(renderer); return; } context = filterData->savedContext; filterData->savedContext = 0; break; case FilterData::Built: { } // Empty } FilterEffect* lastEffect = filterData->builder->lastEffect(); if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) { // This is the real filtering of the object. It just needs to be called on the // initial filtering process. We just take the stored filter result on a // second drawing. if (filterData->state != FilterData::Built) filterData->filter->setSourceImage(WTF::move(filterData->sourceGraphicBuffer)); // Always true if filterData is just built (filterData->state == FilterData::Built). if (!lastEffect->hasResult()) { filterData->state = FilterData::Applying; lastEffect->applyAll(); lastEffect->correctFilterResultIfNeeded(); lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB); } filterData->state = FilterData::Built; ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); context->drawImageBuffer(*resultImage, renderer.style().colorSpace(), lastEffect->absolutePaintRect()); context->scale(filterData->filter->filterResolution()); context->concatCTM(filterData->shearFreeAbsoluteTransform); } } filterData->sourceGraphicBuffer.reset(); }
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, unsigned currentCharacter, unsigned& advanceLength) const { const TextRun& run = iterator.run(); Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms(); ASSERT(run.charactersLength() >= currentCharacter); // Associate text with arabic forms, if needed. String remainingTextInRun; if (run.is8Bit()) { remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter); remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length()); } else { remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter); remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length()); } if (mirror) remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun); if (!currentCharacter && arabicForms.isEmpty()) arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); ASSERT(svgFontFaceElement); SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); ASSERT(associatedFontElement); RenderObject* renderObject = 0; if (TextRun::RenderingContext* renderingContext = run.renderingContext()) renderObject = &static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); String language; bool isVerticalText = false; Vector<String> altGlyphNames; if (renderObject) { RenderElement* parentRenderer = renderObject->isRenderElement() ? toRenderElement(renderObject) : renderObject->parent(); ASSERT(parentRenderer); isVerticalText = parentRenderer->style().svgStyle().isVerticalWritingMode(); if (Element* parentRendererElement = parentRenderer->element()) { language = parentRendererElement->getAttribute(XMLNames::langAttr); if (isSVGAltGlyphElement(parentRendererElement)) { SVGAltGlyphElement* altGlyph = toSVGAltGlyphElement(parentRendererElement); if (!altGlyph->hasValidGlyphElements(altGlyphNames)) altGlyphNames.clear(); } } } Vector<SVGGlyph> glyphs; size_t altGlyphNamesSize = altGlyphNames.size(); if (altGlyphNamesSize) { for (size_t index = 0; index < altGlyphNamesSize; ++index) associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs); // Assign the unicodeStringLength now that its known. size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) glyphs[i].unicodeStringLength = run.length(); // Do not check alt glyphs for compatibility. Just return the first one. // Later code will fail if we do not do this and the glyph is incompatible. if (glyphsSize) { SVGGlyph& svgGlyph = glyphs[0]; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } } else associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs); size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) { SVGGlyph& svgGlyph = glyphs[i]; if (svgGlyph.isPartOfLigature) continue; if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength)) continue; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } iterator.setLastGlyphName(String()); return false; }
void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, int& ascent, int& descent, bool& affectsAscent, bool& affectsDescent) const { bool ascentDescentSet = false; // Replaced boxes will return 0 for the line-height if line-box-contain says they are // not to be included. if (box->renderer().isReplaced()) { if (lineStyle().lineBoxContain() & LineBoxContainReplaced) { ascent = box->baselinePosition(baselineType()); descent = box->lineHeight() - ascent; // Replaced elements always affect both the ascent and descent. affectsAscent = true; affectsDescent = true; } return; } Vector<const SimpleFontData*>* usedFonts = 0; GlyphOverflow* glyphOverflow = 0; if (box->isInlineTextBox()) { GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(toInlineTextBox(box)); usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first; glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second; } bool includeLeading = includeLeadingForBox(box); bool includeFont = includeFontForBox(box); bool setUsedFont = false; bool setUsedFontWithLeading = false; const RenderStyle& boxLineStyle = box->lineStyle(); #if PLATFORM(IOS) if (usedFonts && !usedFonts->isEmpty() && (includeFont || (boxLineStyle.lineHeight().isNegative() && includeLeading)) && !box->renderer().document().settings()->alwaysUseBaselineOfPrimaryFont()) { #else if (usedFonts && !usedFonts->isEmpty() && (includeFont || (boxLineStyle.lineHeight().isNegative() && includeLeading))) { #endif usedFonts->append(boxLineStyle.font().primaryFont()); for (size_t i = 0; i < usedFonts->size(); ++i) { const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics(); int usedFontAscent = fontMetrics.ascent(baselineType()); int usedFontDescent = fontMetrics.descent(baselineType()); int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2; int usedFontAscentAndLeading = usedFontAscent + halfLeading; int usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading; if (includeFont) { setAscentAndDescent(ascent, descent, usedFontAscent, usedFontDescent, ascentDescentSet); setUsedFont = true; } if (includeLeading) { setAscentAndDescent(ascent, descent, usedFontAscentAndLeading, usedFontDescentAndLeading, ascentDescentSet); setUsedFontWithLeading = true; } if (!affectsAscent) affectsAscent = usedFontAscent - box->logicalTop() > 0; if (!affectsDescent) affectsDescent = usedFontDescent + box->logicalTop() > 0; } } // If leading is included for the box, then we compute that box. if (includeLeading && !setUsedFontWithLeading) { int ascentWithLeading = box->baselinePosition(baselineType()); int descentWithLeading = box->lineHeight() - ascentWithLeading; setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet); // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline. // If the top of our font box relative to the root box baseline is above the root box baseline, then // we are contributing to the maxAscent value. Descent is similar. If any part of our font box is below // the root box's baseline, then we contribute to the maxDescent value. affectsAscent = ascentWithLeading - box->logicalTop() > 0; affectsDescent = descentWithLeading + box->logicalTop() > 0; } if (includeFontForBox(box) && !setUsedFont) { int fontAscent = boxLineStyle.fontMetrics().ascent(baselineType()); int fontDescent = boxLineStyle.fontMetrics().descent(baselineType()); setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet); affectsAscent = fontAscent - box->logicalTop() > 0; affectsDescent = fontDescent + box->logicalTop() > 0; } if (includeGlyphsForBox(box) && glyphOverflow && glyphOverflow->computeBounds) { setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet); affectsAscent = glyphOverflow->top - box->logicalTop() > 0; affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0; glyphOverflow->top = std::min(glyphOverflow->top, std::max(0, glyphOverflow->top - boxLineStyle.fontMetrics().ascent(baselineType()))); glyphOverflow->bottom = std::min(glyphOverflow->bottom, std::max(0, glyphOverflow->bottom - boxLineStyle.fontMetrics().descent(baselineType()))); } if (includeMarginForBox(box)) { LayoutUnit ascentWithMargin = boxLineStyle.fontMetrics().ascent(baselineType()); LayoutUnit descentWithMargin = boxLineStyle.fontMetrics().descent(baselineType()); if (box->parent() && !box->renderer().isTextOrLineBreak()) { ascentWithMargin += box->boxModelObject()->borderAndPaddingBefore() + box->boxModelObject()->marginBefore(); descentWithMargin += box->boxModelObject()->borderAndPaddingAfter() + box->boxModelObject()->marginAfter(); } setAscentAndDescent(ascent, descent, ascentWithMargin, descentWithMargin, ascentDescentSet); // Treat like a replaced element, since we're using the margin box. affectsAscent = true; affectsDescent = true; } } LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositionCache& verticalPositionCache) { if (box->renderer().isTextOrLineBreak()) return box->parent()->logicalTop(); RenderBoxModelObject* renderer = box->boxModelObject(); ASSERT(renderer->isInline()); if (!renderer->isInline()) return 0; // This method determines the vertical position for inline elements. bool firstLine = isFirstLine(); if (firstLine && !renderer->document().styleSheetCollection().usesFirstLineRules()) firstLine = false; // Check the cache. bool isRenderInline = renderer->isRenderInline(); if (isRenderInline && !firstLine) { LayoutUnit verticalPosition = verticalPositionCache.get(renderer, baselineType()); if (verticalPosition != PositionUndefined) return verticalPosition; } LayoutUnit verticalPosition = 0; EVerticalAlign verticalAlign = renderer->style().verticalAlign(); if (verticalAlign == TOP || verticalAlign == BOTTOM) return 0; RenderElement* parent = renderer->parent(); if (parent->isRenderInline() && parent->style().verticalAlign() != TOP && parent->style().verticalAlign() != BOTTOM) verticalPosition = box->parent()->logicalTop(); if (verticalAlign != BASELINE) { const RenderStyle& parentLineStyle = firstLine ? parent->firstLineStyle() : parent->style(); const Font& font = parentLineStyle.font(); const FontMetrics& fontMetrics = font.fontMetrics(); int fontSize = font.pixelSize(); LineDirectionMode lineDirection = parent->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; if (verticalAlign == SUB) verticalPosition += fontSize / 5 + 1; else if (verticalAlign == SUPER) verticalPosition -= fontSize / 3 + 1; else if (verticalAlign == TEXT_TOP) verticalPosition += renderer->baselinePosition(baselineType(), firstLine, lineDirection) - fontMetrics.ascent(baselineType()); else if (verticalAlign == MIDDLE) verticalPosition = (verticalPosition - LayoutUnit(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection)).round(); else if (verticalAlign == TEXT_BOTTOM) { verticalPosition += fontMetrics.descent(baselineType()); // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case. if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable()) verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType(), firstLine, lineDirection)); } else if (verticalAlign == BASELINE_MIDDLE) verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection); else if (verticalAlign == LENGTH) { LayoutUnit lineHeight; //Per http://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align: 'Percentages: refer to the 'line-height' of the element itself'. if (renderer->style().verticalAlignLength().isPercent()) lineHeight = renderer->style().computedLineHeight(); else lineHeight = renderer->lineHeight(firstLine, lineDirection); verticalPosition -= valueForLength(renderer->style().verticalAlignLength(), lineHeight); } } // Store the cached value. if (isRenderInline && !firstLine) verticalPositionCache.set(renderer, baselineType(), verticalPosition); return verticalPosition; } bool RootInlineBox::includeLeadingForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return (lineBoxContain & LineBoxContainInline) || (box == this && (lineBoxContain & LineBoxContainBlock)); } bool RootInlineBox::includeFontForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; if (!box->behavesLikeText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren()) return false; // For now map "glyphs" to "font" in vertical text mode until the bounds returned by glyphs aren't garbage. LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return (lineBoxContain & LineBoxContainFont) || (!isHorizontal() && (lineBoxContain & LineBoxContainGlyphs)); } bool RootInlineBox::includeGlyphsForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; if (!box->behavesLikeText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren()) return false; // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage. LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs); } bool RootInlineBox::includeMarginForBox(InlineBox* box) const { if (box->renderer().isReplaced() || (box->renderer().isTextOrLineBreak() && !box->behavesLikeText())) return false; LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return lineBoxContain & LineBoxContainInlineBox; } bool RootInlineBox::fitsToGlyphs() const { // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage. LineBoxContain lineBoxContain = renderer().style().lineBoxContain(); return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs); }
void SVGRenderSupport::styleChanged(RenderElement& renderer) { auto parent = renderer.parent(); SVGRenderSupport::setRendererHasSVGShadow(renderer, (parent && SVGRenderSupport::rendererHasSVGShadow(*parent)) || renderer.style().svgStyle().shadow()); }
std::unique_ptr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderElement& renderer) { if (!renderer.isCSSAnimating()) return RenderStyle::clonePtr(renderer.style()); return m_data->getAnimatedStyleForRenderer(renderer); }
static inline bool hasVisibleTextArea(RenderElement& textControl, TextControlInnerTextElement* innerText) { return textControl.style()->visibility() != HIDDEN && innerText && innerText->renderer() && innerText->renderBox()->height(); }
bool TextAutoSizingValue::adjustNodeSizes() { bool objectsRemoved = false; // Remove stale nodes. Nodes may have had their renderers detached. We'll // also need to remove the style from the documents m_textAutoSizedNodes // collection. Return true indicates we need to do that removal. Vector<RefPtr<Node> > nodesForRemoval; HashSet<RefPtr<Node> >::iterator end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { RefPtr<Node> autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (!text || !text->style().textSizeAdjust().isAuto() || !text->candidateComputedTextSize()) { // remove node. nodesForRemoval.append(autoSizingNode); objectsRemoved = true; } } unsigned count = nodesForRemoval.size(); for (unsigned i = 0; i < count; i++) m_autoSizedNodes.remove(nodesForRemoval[i]); // If we only have one piece of text with the style on the page don't // adjust it's size. if (m_autoSizedNodes.size() <= 1) return objectsRemoved; // Compute average size float cumulativeSize = 0; end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { RefPtr<Node> autoSizingNode = *i; RenderText* renderText = static_cast<RenderText*>(autoSizingNode->renderer()); cumulativeSize += renderText->candidateComputedTextSize(); } float averageSize = roundf(cumulativeSize / m_autoSizedNodes.size()); // Adjust sizes bool firstPass = true; end = m_autoSizedNodes.end(); for (HashSet<RefPtr<Node> >::iterator i = m_autoSizedNodes.begin(); i != end; ++i) { const RefPtr<Node>& autoSizingNode = *i; RenderText* text = static_cast<RenderText*>(autoSizingNode->renderer()); if (text && text->style().fontDescription().computedSize() != averageSize) { float specifiedSize = text->style().fontDescription().specifiedSize(); float scaleChange = averageSize / specifiedSize; if (scaleChange > MAX_SCALE_INCREASE && firstPass) { firstPass = false; averageSize = roundf(specifiedSize * MAX_SCALE_INCREASE); scaleChange = averageSize / specifiedSize; } RefPtr<RenderStyle> style = cloneRenderStyleWithState(text->style()); FontDescription fontDescription = style->fontDescription(); fontDescription.setComputedSize(averageSize); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); text->parent()->setStyle(style.releaseNonNull()); RenderElement* parentRenderer = text->parent(); if (parentRenderer->isAnonymousBlock()) parentRenderer = parentRenderer->parent(); // If we have a list we should resize ListMarkers separately. RenderObject* listMarkerRenderer = parentRenderer->firstChild(); if (listMarkerRenderer->isListMarker()) { RefPtr<RenderStyle> style = cloneRenderStyleWithState(listMarkerRenderer->style()); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); toRenderListMarker(*listMarkerRenderer).setStyle(style.releaseNonNull()); } // Resize the line height of the parent. const RenderStyle& parentStyle = parentRenderer->style(); Length lineHeightLength = parentStyle.specifiedLineHeight(); int specifiedLineHeight = 0; if (lineHeightLength.isPercent()) specifiedLineHeight = minimumValueForLength(lineHeightLength, fontDescription.specifiedSize()); else specifiedLineHeight = lineHeightLength.value(); int lineHeight = specifiedLineHeight * scaleChange; if (!lineHeightLength.isFixed() || lineHeightLength.value() != lineHeight) { RefPtr<RenderStyle> newParentStyle = cloneRenderStyleWithState(parentStyle); newParentStyle->setLineHeight(Length(lineHeight, Fixed)); newParentStyle->setSpecifiedLineHeight(lineHeightLength); newParentStyle->setFontDescription(fontDescription); newParentStyle->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); parentRenderer->setStyle(newParentStyle.releaseNonNull()); } } } return objectsRemoved; }