void RenderTextLineBoxes::removeAllFromParent(RenderText& renderer) { if (!m_first) { if (renderer.parent()) renderer.parent()->dirtyLinesFromChangedChild(&renderer); return; } for (auto box = m_first; box; box = box->nextTextBox()) box->removeFromParent(); }
IntRect computeTextBoundingBox(const RenderText& textRenderer, const Layout& layout) { auto resolver = lineResolver(toRenderBlockFlow(*textRenderer.parent()), layout); auto it = resolver.begin(); auto end = resolver.end(); if (it == end) return IntRect(); auto firstLineRect = *it; float left = firstLineRect.x(); float right = firstLineRect.maxX(); float bottom = firstLineRect.maxY(); for (++it; it != end; ++it) { auto rect = *it; if (rect.x() < left) left = rect.x(); if (rect.maxX() > right) right = rect.maxX(); if (rect.maxY() > bottom) bottom = rect.maxY(); } float x = left; float y = firstLineRect.y(); float width = right - left; float height = bottom - y; return enclosingIntRect(FloatRect(x, y, width, height)); }
IntPoint computeTextFirstRunLocation(const RenderText& textRenderer, const Layout& layout) { auto resolver = runResolver(toRenderBlockFlow(*textRenderer.parent()), layout); auto begin = resolver.begin(); if (begin == resolver.end()) return IntPoint(); return flooredIntPoint((*begin).rect().location()); }
Vector<FloatQuad> collectTextAbsoluteQuads(const RenderText& textRenderer, const Layout& layout, bool* wasFixed) { Vector<FloatQuad> quads; auto resolver = runResolver(toRenderBlockFlow(*textRenderer.parent()), layout); for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { const auto& run = *it; auto rect = run.rect(); quads.append(textRenderer.localToAbsoluteQuad(FloatQuad(rect), 0, wasFixed)); } return quads; }
Vector<IntRect> collectTextAbsoluteRects(const RenderText& textRenderer, const Layout& layout, const LayoutPoint& accumulatedOffset) { Vector<IntRect> rects; auto resolver = runResolver(toRenderBlockFlow(*textRenderer.parent()), layout); for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { const auto& run = *it; auto rect = run.rect(); rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size()))); } return rects; }
void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData, RecalcStyleBehavior recalcStyleBehavior) { if (!inActiveDocument()) return; RenderText* textRenderer = renderer(); if (!textRenderer || !textRendererIsNeeded(*textRenderer->style(), *textRenderer->parent())) { lazyReattachIfAttached(); // FIXME: Editing should be updated so this is not neccesary. if (recalcStyleBehavior == DeprecatedRecalcStyleImmediatlelyForEditing) document().updateRenderTreeIfNeeded(); return; } textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData); }
void TextAutoSizingValue::reset() { HashSet<RefPtr<Node> >::iterator 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) continue; // Reset the font size back to the original specified size FontDescription fontDescription = text->style().fontDescription(); float originalSize = fontDescription.specifiedSize(); if (fontDescription.computedSize() != originalSize) { fontDescription.setComputedSize(originalSize); RefPtr<RenderStyle> style = cloneRenderStyleWithState(text->style()); style->setFontDescription(fontDescription); style->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); text->parent()->setStyle(style.releaseNonNull()); } // Reset the line height of the parent. RenderElement* parentRenderer = text->parent(); if (!parentRenderer) continue; if (parentRenderer->isAnonymousBlock()) parentRenderer = parentRenderer->parent(); const RenderStyle& parentStyle = parentRenderer->style(); Length originalLineHeight = parentStyle.specifiedLineHeight(); if (originalLineHeight != parentStyle.lineHeight()) { RefPtr<RenderStyle> newParentStyle = cloneRenderStyleWithState(parentStyle); newParentStyle->setLineHeight(originalLineHeight); newParentStyle->setFontDescription(fontDescription); newParentStyle->font().update(autoSizingNode->document().ensureStyleResolver().fontSelector()); parentRenderer->setStyle(newParentStyle.releaseNonNull()); } } }
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; }
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; }