String HitTestResult::innerTextIfTruncated(TextDirection& dir) const { for (Node* truncatedNode = m_innerNode.get(); truncatedNode; truncatedNode = truncatedNode->parentNode()) { if (!truncatedNode->isElementNode()) continue; if (RenderObject* renderer = truncatedNode->renderer()) { if (renderer->isRenderBlock()) { RenderBlock* block = toRenderBlock(renderer); if (block->style()->textOverflow()) { for (RootInlineBox* line = block->firstRootBox(); line; line = line->nextRootBox()) { if (line->hasEllipsisBox()) { dir = block->style()->direction(); return toElement(truncatedNode)->innerText(); } } } break; } } } dir = LTR; return String(); }
void findGoodTouchTargets(const IntRect& touchBox, LocalFrame* mainFrame, Vector<IntRect>& goodTargets, WillBeHeapVector<RawPtrWillBeMember<Node> >& highlightNodes) { goodTargets.clear(); int touchPointPadding = ceil(std::max(touchBox.width(), touchBox.height()) * 0.5); IntPoint touchPoint = touchBox.center(); IntPoint contentsPoint = mainFrame->view()->windowToContents(touchPoint); HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(contentsPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, IntSize(touchPointPadding, touchPointPadding)); const WillBeHeapListHashSet<RefPtrWillBeMember<Node> >& hitResults = result.rectBasedTestResult(); // Blacklist nodes that are container of disambiguated nodes. // It is not uncommon to have a clickable <div> that contains other clickable objects. // This heuristic avoids excessive disambiguation in that case. WillBeHeapHashSet<RawPtrWillBeMember<Node> > blackList; for (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) { // Ignore any Nodes that can't be clicked on. RenderObject* renderer = it->get()->renderer(); if (!renderer || !it->get()->willRespondToMouseClickEvents()) continue; // Blacklist all of the Node's containers. for (RenderBlock* container = renderer->containingBlock(); container; container = container->containingBlock()) { Node* containerNode = container->node(); if (!containerNode) continue; if (!blackList.add(containerNode).isNewEntry) break; } } WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData> touchTargets; float bestScore = 0; for (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) { for (Node* node = it->get(); node; node = node->parentNode()) { if (blackList.contains(node)) continue; if (node->isDocumentNode() || isHTMLHtmlElement(*node) || isHTMLBodyElement(*node)) break; if (node->willRespondToMouseClickEvents()) { TouchTargetData& targetData = touchTargets.add(node, TouchTargetData()).storedValue->value; targetData.windowBoundingBox = boundingBoxForEventNodes(node); targetData.score = scoreTouchTarget(touchPoint, touchPointPadding, targetData.windowBoundingBox); bestScore = std::max(bestScore, targetData.score); break; } } } for (WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData>::iterator it = touchTargets.begin(); it != touchTargets.end(); ++it) { // Currently the scoring function uses the overlap area with the fat point as the score. // We ignore the candidates that has less than 1/2 overlap (we consider not really ambiguous enough) than the best candidate to avoid excessive popups. if (it->value.score < bestScore * 0.5) continue; goodTargets.append(it->value.windowBoundingBox); highlightNodes.append(it->key); } }
int InlineTextBox::textPos() const { if (xPos() == 0) return 0; RenderBlock *blockElement = object()->containingBlock(); return direction() == RTL ? xPos() - blockElement->borderRight() - blockElement->paddingRight() : xPos() - blockElement->borderLeft() - blockElement->paddingLeft(); }
RenderObject *ElementImpl::createRenderer(RenderArena *arena, RenderStyle *style) { if (getDocument()->documentElement() == this && style->display() == NONE) { // Ignore display: none on root elements. Force a display of block in that case. RenderBlock* result = new (arena) RenderBlock(this); if (result) result->setStyle(style); return result; } return RenderObject::createObject(this, style); }
FloatPoint InlineBox::locationIncludingFlipping() { if (!renderer()->style()->isFlippedBlocksWritingMode()) return FloatPoint(x(), y()); RenderBlock* block = root()->block(); if (block->style()->isHorizontalWritingMode()) return FloatPoint(x(), block->height() - height() - y()); else return FloatPoint(block->width() - width() - x(), y()); }
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. RenderMathMLBlock* wrapper = new (renderArena()) RenderMathMLBlock(node()); RefPtr<RenderStyle> wrapperStyle = RenderStyle::create(); wrapperStyle->inheritFrom(style()); wrapperStyle->setDisplay(INLINE_BLOCK); wrapperStyle->setVerticalAlign(BASELINE); wrapper->setStyle(wrapperStyle.release()); RenderMathMLBlock::addChild(wrapper, firstChild()); wrapper->addChild(child); // Make sure we have a script block for rendering. if (m_kind == SubSup && !m_scripts) { m_scripts = new (renderArena()) RenderMathMLBlock(node()); RefPtr<RenderStyle> scriptsStyle = RenderStyle::create(); scriptsStyle->inheritFrom(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->setStyle(scriptsStyle.release()); RenderMathMLBlock::addChild(m_scripts, beforeChild); } } else { if (m_kind == SubSup) { ASSERT(childElement); if (!childElement) return; RenderBlock* script = new (renderArena()) RenderMathMLBlock(node()); RefPtr<RenderStyle> scriptStyle = RenderStyle::create(); scriptStyle->inheritFrom(m_scripts->style()); scriptStyle->setDisplay(BLOCK); script->setStyle(scriptStyle.release()); // 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); } }
static bool shouldScaleColumns(RenderTable* table) { // A special case. If this table is not fixed width and contained inside // a cell, then don't bloat the maxwidth by examining percentage growth. bool scale = true; while (table) { Length tw = table->style()->width(); if ((tw.isVariable() || tw.isPercent()) && !table->isPositioned()) { RenderBlock* cb = table->containingBlock(); while (cb && !cb->isCanvas() && !cb->isTableCell() && cb->style()->width().isVariable() && !cb->isPositioned()) cb = cb->containingBlock(); table = 0; if (cb && cb->isTableCell() && (cb->style()->width().isVariable() || cb->style()->width().isPercent())) { if (tw.isPercent()) scale = false; else { RenderTableCell* cell = static_cast<RenderTableCell*>(cb); if (cell->colSpan() > 1 || cell->table()->style()->width().isVariable()) scale = false; else table = cell->table(); } } } else table = 0; } return scale; }
void InlinePainter::paintOutline(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { RenderStyle* styleToUse = m_renderInline.style(); if (!styleToUse->hasOutline()) return; LayoutRect bounds; if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { // FIXME: Use tighter bounds. RenderBlock* cb = m_renderInline.containingBlock(); bounds = cb->visualOverflowRect(); bounds.moveBy(paintOffset); } RenderDrawingRecorder recorder(paintInfo.context, m_renderInline, paintInfo.phase, bounds); if (recorder.canUseCachedDrawing()) return; if (styleToUse->outlineStyleIsAuto()) { if (RenderTheme::theme().shouldDrawDefaultFocusRing(&m_renderInline)) { // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. ObjectPainter(m_renderInline).paintFocusRing(paintInfo, paintOffset, styleToUse); } return; } if (styleToUse->outlineStyle() == BNONE) return; Vector<LayoutRect> rects; rects.append(LayoutRect()); for (InlineFlowBox* curr = m_renderInline.firstLineBox(); curr; curr = curr->nextLineBox()) { RootInlineBox& root = curr->root(); LayoutUnit top = std::max<LayoutUnit>(root.lineTop(), curr->logicalTop()); LayoutUnit bottom = std::min<LayoutUnit>(root.lineBottom(), curr->logicalBottom()); rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top)); } rects.append(LayoutRect()); Color outlineColor = m_renderInline.resolveColor(styleToUse, CSSPropertyOutlineColor); bool useTransparencyLayer = outlineColor.hasAlpha(); GraphicsContext* graphicsContext = paintInfo.context; if (useTransparencyLayer) { graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255); outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue()); } for (unsigned i = 1; i < rects.size() - 1; i++) paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor); if (useTransparencyLayer) graphicsContext->endLayer(); }
VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point, const RenderRegion*) { if (!firstTextBox() || !textLength()) return createVisiblePosition(0, DOWNSTREAM); float baseline = m_scaledFont.fontMetrics().floatAscent(); RenderBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates. FloatPoint absolutePoint(point); absolutePoint.moveBy(containingBlock->location()); float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; const SVGTextFragment* closestDistanceFragment = nullptr; SVGInlineTextBox* closestDistanceBox = nullptr; AffineTransform fragmentTransform; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { if (!is<SVGInlineTextBox>(*box)) continue; auto& textBox = downcast<SVGInlineTextBox>(*box); Vector<SVGTextFragment>& fragments = textBox.textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) + powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2); if (distance < closestDistance) { closestDistance = distance; closestDistanceBox = &textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } } } if (!closestDistanceFragment) return createVisiblePosition(0, DOWNSTREAM); int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true); return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); }
LayoutUnit RenderBlockFlow::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) { LayoutUnit logicalRight = logicalRightOffsetForLine(false); if (logicalRight == logicalRightOffsetForContent()) return RenderBlock::logicalRightSelectionOffset(rootBlock, position); RenderBlock* cb = this; while (cb != rootBlock) { logicalRight += cb->logicalLeft(); cb = cb->containingBlock(); } return logicalRight; }
VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) { if (!firstTextBox() || !textLength()) return createVisiblePosition(0, DOWNSTREAM); RenderStyle* style = this->style(); ASSERT(style); int baseline = style->font().ascent(); RenderBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates. FloatPoint absolutePoint(point); absolutePoint.move(containingBlock->x(), containingBlock->y()); float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; const SVGTextFragment* closestDistanceFragment = 0; SVGInlineTextBox* closestDistanceBox = 0; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { ASSERT(box->isSVGInlineTextBox()); SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box); Vector<SVGTextFragment>& fragments = textBox->textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); if (!fragment.transform.isIdentity()) fragmentRect = fragment.transform.mapRect(fragmentRect); float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) + powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2); if (distance < closestDistance) { closestDistance = distance; closestDistanceBox = textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } } } if (!closestDistanceFragment) return createVisiblePosition(0, DOWNSTREAM); int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true); return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); }
void RenderLineBreak::collectSelectionRects(Vector<SelectionRect>& rects, unsigned, unsigned) { ensureLineBoxes(*this); InlineElementBox* box = m_inlineBoxWrapper; if (!box) return; const RootInlineBox& rootBox = box->root(); LayoutRect rect = rootBox.computeCaretRect(box->logicalLeft(), 0, nullptr); if (rootBox.isFirstAfterPageBreak()) { if (box->isHorizontal()) rect.shiftYEdgeTo(rootBox.lineTopWithLeading()); else rect.shiftXEdgeTo(rootBox.lineTopWithLeading()); } RenderBlock* containingBlock = this->containingBlock(); // Map rect, extended left to leftOffset, and right to rightOffset, through transforms to get minX and maxX. LogicalSelectionOffsetCaches cache(*containingBlock); LayoutUnit leftOffset = containingBlock->logicalLeftSelectionOffset(*containingBlock, box->logicalTop(), cache); LayoutUnit rightOffset = containingBlock->logicalRightSelectionOffset(*containingBlock, box->logicalTop(), cache); LayoutRect extentsRect = rect; if (box->isHorizontal()) { extentsRect.setX(leftOffset); extentsRect.setWidth(rightOffset - leftOffset); } else { extentsRect.setY(leftOffset); extentsRect.setHeight(rightOffset - leftOffset); } extentsRect = localToAbsoluteQuad(FloatRect(extentsRect)).enclosingBoundingBox(); if (!box->isHorizontal()) extentsRect = extentsRect.transposedRect(); bool isFirstOnLine = !box->previousOnLineExists(); bool isLastOnLine = !box->nextOnLineExists(); if (containingBlock->isRubyBase() || containingBlock->isRubyText()) isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists(); bool isFixed = false; IntRect absRect = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed).enclosingBoundingBox(); bool boxIsHorizontal = !box->isSVGInlineTextBox() ? box->isHorizontal() : !style().svgStyle().isVerticalWritingMode(); // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to // determine if the element is the last on the line. if (containingBlock->inlineBoxWrapper()) { if (containingBlock->inlineBoxWrapper()->isHorizontal() != boxIsHorizontal) { boxIsHorizontal = containingBlock->inlineBoxWrapper()->isHorizontal(); isLastOnLine = !containingBlock->inlineBoxWrapper()->nextOnLineExists(); } } rects.append(SelectionRect(absRect, box->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, box->isLineBreak(), isFirstOnLine, isLastOnLine, false, false, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absRect.x()))); }
int RenderSVGContainer::calcReplacedHeight() const { switch (style()->height().type()) { case Fixed: return max(0, style()->height().value()); case Percent: { RenderBlock* cb = containingBlock(); return style()->height().calcValue(cb->availableHeight()); } default: return 0; } }
IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { // Only run-ins are allowed in here during layout. ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn()); if (!firstLineBox() && !continuation()) return IntRect(); // Find our leftmost position. IntRect boundingBox(linesBoundingBox()); int left = boundingBox.x(); int top = boundingBox.y(); // Now invalidate a rectangle. int ow = style() ? style()->outlineSize() : 0; // We need to add in the relative position offsets of any inlines (including us) up to our // containing block. RenderBlock* cb = containingBlock(); for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; inlineFlow = inlineFlow->parent()) { if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) toRenderBox(inlineFlow)->layer()->relativePositionOffset(left, top); } IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2); if (cb->hasColumns()) cb->adjustRectForColumns(r); if (cb->hasOverflowClip()) { // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. int x = r.x(); int y = r.y(); IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height()); cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. IntRect repaintRect(x, y, r.width(), r.height()); r = intersection(repaintRect, boxRect); } ASSERT(repaintContainer != this); cb->computeRectForRepaint(r, repaintContainer); if (ow) { for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { if (!curr->isText()) { IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow); r.unite(childRect); } } if (continuation() && !continuation()->isInline()) { IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow); r.unite(contRect); } } return r; }
static inline RenderBlock* firstContainingBlockWithLogicalWidth(const RenderReplaced* replaced) { // We have to lookup the containing block, which has an explicit width, which must not be equal to our direct containing block. // If the embedded document appears _after_ we performed the initial layout, our intrinsic size is 300x150. If our containing // block doesn't provide an explicit width, it's set to the 300 default, coming from the initial layout run. RenderBlock* containingBlock = replaced->containingBlock(); if (!containingBlock) return 0; for (; containingBlock && !is<RenderView>(*containingBlock) && !containingBlock->isBody(); containingBlock = containingBlock->containingBlock()) { if (containingBlock->style().logicalWidth().isSpecified()) return containingBlock; } return 0; }
void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); if (m_innerText) { RenderBlock* textBlockRenderer = toRenderBlock(m_innerText->renderer()); RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(style()); // We may have set the width and the height in the old style in layout(). // Reset them now to avoid getting a spurious layout hint. textBlockRenderer->style()->setHeight(Length()); textBlockRenderer->style()->setWidth(Length()); setInnerTextStyle(textBlockStyle); } setReplaced(isInline()); }
FloatQuad RenderSVGInlineText::computeRepaintQuadForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos) { RenderBlock* cb = containingBlock(); if (!cb || !cb->container()) return FloatQuad(); RenderSVGRoot* root = findSVGRootObject(parent()); if (!root) return FloatQuad(); IntRect rect; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) rect.unite(box->selectionRect(0, 0, startPos, endPos)); return localToContainerQuad(FloatQuad(rect), repaintContainer); }
VisiblePosition RenderInline::positionForCoordinates(int x, int y) { // Translate the coords from the pre-anonymous block to the post-anonymous block. RenderBlock* cb = containingBlock(); int parentBlockX = cb->xPos() + x; int parentBlockY = cb->yPos() + y; for (RenderObject* c = continuation(); c; c = c->continuation()) { RenderObject* contBlock = c; if (c->isInline()) contBlock = c->containingBlock(); if (c->isInline() || c->firstChild()) return c->positionForCoordinates(parentBlockX - contBlock->xPos(), parentBlockY - contBlock->yPos()); } return RenderFlow::positionForCoordinates(x, y); }
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); } }
bool RenderVTTCue::initializeLayoutParameters(InlineFlowBox*& firstLineBox, LayoutUnit& step, LayoutUnit& position) { ASSERT(firstChild()); RenderBlock* parentBlock = containingBlock(); firstLineBox = toRenderInline(firstChild())->firstLineBox(); if (!firstLineBox) firstLineBox = this->firstRootBox(); // 1. Horizontal: Let step be the height of the first line box in boxes. // Vertical: Let step be the width of the first line box in boxes. step = m_cue->getWritingDirection() == VTTCue::Horizontal ? firstLineBox->height() : firstLineBox->width(); // 2. If step is zero, then jump to the step labeled done positioning below. if (!step) return false; // 3. Let line position be the text track cue computed line position. int linePosition = m_cue->calculateComputedLinePosition(); // 4. Vertical Growing Left: Add one to line position then negate it. if (m_cue->getWritingDirection() == VTTCue::VerticalGrowingLeft) linePosition = -(linePosition + 1); // 5. Let position be the result of multiplying step and line position. position = step * linePosition; // 6. Vertical Growing Left: Decrease position by the width of the // bounding box of the boxes in boxes, then increase position by step. if (m_cue->getWritingDirection() == VTTCue::VerticalGrowingLeft) { position -= width(); position += step; } // 7. If line position is less than zero... if (linePosition < 0) { // Horizontal / Vertical: ... then increase position by the // height / width of the video's rendering area ... position += m_cue->getWritingDirection() == VTTCue::Horizontal ? parentBlock->height() : parentBlock->width(); // ... and negate step. step = -step; } return true; }
void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); Element* innerText = innerTextElement(); if (!innerText) return; RenderBlock* innerTextRenderer = toRenderBlock(innerText->renderer()); if (innerTextRenderer) { // We may have set the width and the height in the old style in layout(). // Reset them now to avoid getting a spurious layout hint. innerTextRenderer->style()->setHeight(Length()); innerTextRenderer->style()->setWidth(Length()); innerTextRenderer->setStyle(createInnerTextStyle(style())); innerText->setNeedsStyleRecalc(); } textFormControlElement()->updatePlaceholderVisibility(false); }
void FullscreenElementStack::setFullScreenRenderer(RenderFullScreen* renderer) { if (renderer == m_fullScreenRenderer) return; if (renderer && m_savedPlaceholderRenderStyle) { renderer->createPlaceholder(m_savedPlaceholderRenderStyle.release(), m_savedPlaceholderFrameRect); } else if (renderer && m_fullScreenRenderer && m_fullScreenRenderer->placeholder()) { RenderBlock* placeholder = m_fullScreenRenderer->placeholder(); renderer->createPlaceholder(RenderStyle::clone(placeholder->style()), placeholder->frameRect()); } if (m_fullScreenRenderer) m_fullScreenRenderer->destroy(); ASSERT(!m_fullScreenRenderer); m_fullScreenRenderer = renderer; }
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); } }
InlineBox* EllipsisBox::markupBox() const { if (!m_shouldPaintMarkupBox || !m_renderer->isRenderBlock()) return 0; RenderBlock* block = toRenderBlock(m_renderer); RootInlineBox* lastLine = block->lineAtIndex(block->lineCount() - 1); if (!lastLine) return 0; // If the last line-box on the last line of a block is a link, -webkit-line-clamp paints that box after the ellipsis. // It does not actually move the link. InlineBox* anchorBox = lastLine->lastChild(); if (!anchorBox || !anchorBox->renderer()->style()->isLink()) return 0; return anchorBox; }
void RenderBoxModelObject::setSelectionState(SelectionState state) { if (state == SelectionInside && selectionState() != SelectionNone) return; if ((state == SelectionStart && selectionState() == SelectionEnd) || (state == SelectionEnd && selectionState() == SelectionStart)) RenderObject::setSelectionState(SelectionBoth); else RenderObject::setSelectionState(state); // FIXME: We should consider whether it is OK propagating to ancestor RenderInlines. // This is a workaround for http://webkit.org/b/32123 // The containing block can be null in case of an orphaned tree. RenderBlock* containingBlock = this->containingBlock(); if (containingBlock && !containingBlock->isRenderView()) containingBlock->setSelectionState(state); }
RenderObject* RenderRubyRun::removeChild(RenderObject& child) { // If the child is a ruby text, then merge the ruby base with the base of // the right sibling run, if possible. if (!beingDestroyed() && !documentBeingDestroyed() && child.isRubyText()) { RenderRubyBase* base = rubyBase(); RenderObject* rightNeighbour = nextSibling(); if (base && rightNeighbour && rightNeighbour->isRubyRun()) { // Ruby run without a base can happen only at the first run. RenderRubyRun* rightRun = toRenderRubyRun(rightNeighbour); if (rightRun->hasRubyBase()) { RenderRubyBase* rightBase = rightRun->rubyBaseSafe(); // Collect all children in a single base, then swap the bases. rightBase->mergeChildrenWithBase(base); moveChildTo(rightRun, base); rightRun->moveChildTo(this, rightBase); // The now empty ruby base will be removed below. ASSERT(!rubyBase()->firstChild()); } } } RenderObject* next = RenderBlockFlow::removeChild(child); if (!beingDestroyed() && !documentBeingDestroyed()) { // Check if our base (if any) is now empty. If so, destroy it. RenderBlock* base = rubyBase(); if (base && !base->firstChild()) { next = RenderBlockFlow::removeChild(*base); base->deleteLines(); base->destroy(); } // If any of the above leaves the run empty, destroy it as well. if (isEmpty()) { parent()->removeChild(*this); deleteLines(); destroy(); next = nullptr; } } return next; }
LayoutUnit RenderFlowThread::offsetFromLogicalTopOfFirstRegion(const RenderBlock* currentBlock) const { // First check if we cached the offset for the block if it's an ancestor containing block of the box // being currently laid out. LayoutUnit offset; if (cachedOffsetFromLogicalTopOfFirstRegion(currentBlock, offset)) return offset; // If it's the current box being laid out, use the layout state. const RenderBox* currentBoxDescendant = currentStatePusherRenderBox(); if (currentBlock == currentBoxDescendant) { LayoutState* layoutState = view()->layoutState(); ASSERT(layoutState->renderer() == currentBlock); ASSERT(layoutState && layoutState->isPaginated()); LayoutSize offsetDelta = layoutState->layoutOffset() - layoutState->pageOffset(); return currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width(); } // As a last resort, take the slow path. LayoutRect blockRect(0, 0, currentBlock->width(), currentBlock->height()); while (currentBlock && !currentBlock->isRenderFlowThread()) { RenderBlock* containerBlock = currentBlock->containingBlock(); ASSERT(containerBlock); if (!containerBlock) return 0; LayoutPoint currentBlockLocation = currentBlock->location(); if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) { // We have to put the block rect in container coordinates // and we have to take into account both the container and current block flipping modes if (containerBlock->style()->isFlippedBlocksWritingMode()) { if (containerBlock->isHorizontalWritingMode()) blockRect.setY(currentBlock->height() - blockRect.maxY()); else blockRect.setX(currentBlock->width() - blockRect.maxX()); } currentBlock->flipForWritingMode(blockRect); } blockRect.moveBy(currentBlockLocation); currentBlock = containerBlock; } return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x(); }
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(); } }
String HTMLTextFormControlElement::valueWithHardLineBreaks() const { // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer. // While we have no evidence this has ever been a practical problem, it would be best to fix it some day. HTMLElement* innerText = innerTextElement(); if (!innerText || !isTextFormControl()) return value(); RenderBlock* renderer = toRenderBlock(innerText->renderer()); if (!renderer) return value(); Node* breakNode; unsigned breakOffset; RootInlineBox* line = renderer->firstRootBox(); if (!line) return value(); getNextSoftBreak(line, breakNode, breakOffset); StringBuilder result; for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) { if (node->hasTagName(brTag)) result.append(newlineCharacter); else if (node->isTextNode()) { String data = toText(node)->data(); unsigned length = data.length(); unsigned position = 0; while (breakNode == node && breakOffset <= length) { if (breakOffset > position) { result.append(data.characters() + position, breakOffset - position); position = breakOffset; result.append(newlineCharacter); } getNextSoftBreak(line, breakNode, breakOffset); } result.append(data.characters() + position, length - position); } while (breakNode == node) getNextSoftBreak(line, breakNode, breakOffset); } return finishText(result); }
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()); }