WebRenderObject::WebRenderObject(RenderObject* renderer) { m_name = renderer->renderName(); // FIXME: broken with transforms m_absolutePosition = flooredIntPoint(renderer->localToAbsolute(FloatPoint())); if (renderer->isBox()) m_frameRect = toRenderBox(renderer)->frameRect(); else if (renderer->isText()) { m_frameRect = toRenderText(renderer)->linesBoundingBox(); m_frameRect.setX(toRenderText(renderer)->firstRunX()); m_frameRect.setY(toRenderText(renderer)->firstRunY()); } else if (renderer->isRenderInline()) m_frameRect = toRenderBoxModelObject(renderer)->borderBoundingBox(); m_children = MutableArray::create(); for (RenderObject* coreChild = renderer->firstChild(); coreChild; coreChild = coreChild->nextSibling()) { RefPtr<WebRenderObject> child = adoptRef(new WebRenderObject(coreChild)); m_children->append(child.get()); } if (!renderer->isWidget()) return; Widget* widget = toRenderWidget(renderer)->widget(); if (!widget || !widget->isFrameView()) return; FrameView* frameView = static_cast<FrameView*>(widget); if (RenderView* coreContentRenderer = frameView->frame()->contentRenderer()) { RefPtr<WebRenderObject> contentRenderer = adoptRef(new WebRenderObject(coreContentRenderer)); m_children->append(contentRenderer.get()); } }
void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild) { bool needsTable = false; if (newChild->isListItem()) updateListMarkerNumbers(beforeChild ? beforeChild : children()->lastChild()); else if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) needsTable = !isTable(); else if (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) needsTable = !isTable(); else if (newChild->isTableSection()) needsTable = !isTable(); else if (newChild->isTableRow()) needsTable = !isTableSection(); else if (newChild->isTableCell()) { needsTable = !isTableRow(); // I'm not 100% sure this is the best way to fix this, but without this // change we recurse infinitely when trying to render the CSS2 test page: // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html. // See Radar 2925291. if (needsTable && isTableCell() && !children()->firstChild() && !newChild->isTableCell()) needsTable = false; } if (needsTable) { RenderTable* table; RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : children()->lastChild(); if (afterChild && afterChild->isAnonymous() && afterChild->isTable()) table = static_cast<RenderTable*>(afterChild); else { table = new (renderArena()) RenderTable(document() /* is anonymous */); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); newStyle->setDisplay(TABLE); table->setStyle(newStyle.release()); addChild(table, beforeChild); } table->addChild(newChild); } else { // just add it... children()->insertChildNode(this, newChild, beforeChild); } if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText(); if (textToTransform) toRenderText(newChild)->setText(textToTransform.release(), true); } }
void CharacterData::updateRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData) { if ((!renderer() || !rendererIsNeeded(NodeRenderingContext(this, renderer()->style()))) && attached()) reattach(); else if (renderer()) toRenderText(renderer())->setTextWithOffset(m_data.impl(), offsetOfReplacedData, lengthOfReplacedData); }
void TextAutoSizingValue::addNode(Node* node, float size) { ASSERT(node); RenderText* renderText = toRenderText(node->renderer()); renderText->setCandidateComputedTextSize(size); m_autoSizedNodes.add(node); }
void CharacterData::replaceData(unsigned offset, unsigned count, const String& arg, ExceptionCode& ec) { checkCharDataOperation(offset, ec); if (ec) return; unsigned realCount; if (offset + count > length()) realCount = length() - offset; else realCount = count; String newStr = m_data; newStr.remove(offset, realCount); newStr.insert(arg, offset); RefPtr<StringImpl> oldStr = m_data; m_data = newStr.impl(); if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) { detach(); attach(); } else if (renderer()) toRenderText(renderer())->setTextWithOffset(m_data, offset, count); dispatchModifiedEvent(oldStr.get()); // update the markers for spell checking and grammar checking document()->textRemoved(this, offset, realCount); document()->textInserted(this, offset, arg.length()); }
void visibleTextQuads(const Range& range, Vector<FloatQuad>& quads, bool useSelectionHeight) { // Range::textQuads includes hidden text, which we don't want. // To work around this, this is a copy of it which skips hidden elements. Node* startContainer = range.startContainer(); Node* endContainer = range.endContainer(); if (!startContainer || !endContainer) return; Node* stopNode = range.pastLastNode(); for (Node* node = range.firstNode(); node != stopNode; node = node->traverseNextNode()) { RenderObject* r = node->renderer(); if (!r || !r->isText()) continue; if (r->style()->visibility() != VISIBLE) continue; RenderText* renderText = toRenderText(r); int startOffset = node == startContainer ? range.startOffset() : 0; int endOffset = node == endContainer ? range.endOffset() : std::numeric_limits<int>::max(); renderText->absoluteQuadsForRange(quads, startOffset, endOffset, useSelectionHeight); } }
PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionState& exceptionState) { // IndexSizeError: Raised if the specified offset is negative or greater than // the number of 16-bit units in data. if (offset > length()) { exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is larger than the Text node's length."); return 0; } EventQueueScope scope; String oldStr = data(); RefPtr<Text> newText = cloneWithData(oldStr.substring(offset)); setDataWithoutUpdate(oldStr.substring(0, offset)); didModifyData(oldStr); if (parentNode()) parentNode()->insertBefore(newText.get(), nextSibling(), exceptionState); if (exceptionState.hadException()) return 0; if (renderer()) toRenderText(renderer())->setTextWithOffset(dataImpl(), 0, oldStr.length()); if (parentNode()) document().didSplitTextNode(this); return newText.release(); }
bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { if (hitTestAction != HitTestForeground) return false; if (!layout.runCount()) return false; RenderStyle& style = flow.style(); if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE) return false; RenderText& textRenderer = toRenderText(*flow.firstChild()); LayoutRect rangeRect = locationInContainer.boundingBox(); rangeRect.moveBy(-accumulatedOffset); auto resolver = lineResolver(flow, layout); auto range = resolver.rangeForRect(rangeRect); for (auto it = range.begin(), end = range.end(); it != end; ++it) { auto lineRect = *it; lineRect.moveBy(accumulatedOffset); if (!locationInContainer.intersects(lineRect)) continue; textRenderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToRectBasedTestResult(textRenderer.textNode(), request, locationInContainer, lineRect)) return true; } return false; }
PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec) { ec = 0; // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than // the number of 16-bit units in data. if (offset > m_data->length()) { ec = INDEX_SIZE_ERR; return 0; } RefPtr<StringImpl> oldStr = m_data; RefPtr<Text> newText = createNew(oldStr->substring(offset)); m_data = oldStr->substring(0, offset); dispatchModifiedEvent(oldStr.get()); if (parentNode()) parentNode()->insertBefore(newText.get(), nextSibling(), ec); if (ec) return 0; if (parentNode()) document()->textNodeSplit(this); if (renderer()) toRenderText(renderer())->setText(m_data); return newText.release(); }
void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionCode& ec) { checkCharDataOperation(offset, ec); if (ec) return; unsigned realCount; if (offset + count > length()) realCount = length() - offset; else realCount = count; String newStr = m_data; newStr.remove(offset, realCount); RefPtr<StringImpl> oldStr = m_data; m_data = newStr.impl(); if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) { detach(); attach(); } else if (renderer()) toRenderText(renderer())->setTextWithOffset(m_data, offset, count); dispatchModifiedEvent(oldStr.get()); document()->textRemoved(this, offset, realCount); }
PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec) { ec = 0; if (this->parent()) {if (!RO_check(this->parent())) return 0;} // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than // the number of 16-bit units in data. if (offset > length()) { ec = INDEX_SIZE_ERR; return 0; } RefPtr<StringImpl> oldStr = dataImpl(); RefPtr<Text> newText = virtualCreate(oldStr->substring(offset)); setDataImpl(oldStr->substring(0, offset)); dispatchModifiedEvent(oldStr.get()); if (parentNode()) parentNode()->insertBefore(newText.get(), nextSibling(), ec); if (ec) return 0; if (parentNode()) document()->textNodeSplit(this); if (renderer()) toRenderText(renderer())->setTextWithOffset(dataImpl(), 0, oldStr->length()); return newText.release(); }
void CharacterData::updateRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData) { if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) { detach(); attach(); } else if (renderer()) toRenderText(renderer())->setTextWithOffset(m_data, offsetOfReplacedData, lengthOfReplacedData); }
RenderSelectionInfo::RenderSelectionInfo(RenderObject& renderer, bool clipToVisibleContent) : RenderSelectionInfoBase(renderer) { if (renderer.canUpdateSelectionOnRootLineBoxes()) { if (renderer.isText()) m_rect = toRenderText(renderer).collectSelectionRectsForLineBoxes(m_repaintContainer, clipToVisibleContent, m_collectedSelectionRects); else m_rect = renderer.selectionRectForRepaint(m_repaintContainer, clipToVisibleContent); } }
void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const { ASSERT(!needsLayout()); startOverhang = 0; endOverhang = 0; RenderRubyBase* rubyBase = this->rubyBase(); RenderRubyText* rubyText = this->rubyText(); if (!rubyBase || !rubyText) return; if (!rubyBase->firstRootBox()) return; int logicalWidth = this->logicalWidth(); int logicalLeftOverhang = numeric_limits<int>::max(); int logicalRightOverhang = numeric_limits<int>::max(); for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) { logicalLeftOverhang = min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft()); logicalRightOverhang = min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight()); } startOverhang = style()->isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang; endOverhang = style()->isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang; if (!startRenderer || !startRenderer->isText() || startRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize()) startOverhang = 0; if (!endRenderer || !endRenderer->isText() || endRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize()) endOverhang = 0; // We overhang a ruby only if the neighboring render object is a text. // We can overhang the ruby by no more than half the width of the neighboring text // and no more than half the font size. int halfWidthOfFontSize = rubyText->style(firstLine)->fontSize() / 2; if (startOverhang) startOverhang = min<int>(startOverhang, min<int>(toRenderText(startRenderer)->minLogicalWidth(), halfWidthOfFontSize)); if (endOverhang) endOverhang = min<int>(endOverhang, min<int>(toRenderText(endRenderer)->minLogicalWidth(), halfWidthOfFontSize)); }
void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData) { if (!attached()) return; RenderText* textRenderer = toRenderText(renderer()); if (!textRenderer || !textRendererIsNeeded(NodeRenderingContext(this, textRenderer->style()))) { reattach(); return; } textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData); }
BidiRun::BidiRun(int start, int stop, RenderObject& renderer, BidiContext* context, UCharDirection dir) : BidiCharacterRun(start, stop, context, dir) , m_renderer(renderer) , m_box(nullptr) { #ifndef NDEBUG bidiRunCounter.increment(); #endif ASSERT(!m_renderer.isText() || static_cast<unsigned>(stop) <= toRenderText(m_renderer).textLength()); // Stored in base class to save space. m_hasHyphen = false; }
static void writeCounterValuesFromChildren(TextStream& stream, RenderObject* parent, bool& isFirstCounter) { for (RenderObject* child = parent->firstChild(); child; child = child->nextSibling()) { if (child->isCounter()) { if (!isFirstCounter) stream << " "; isFirstCounter = false; String str(toRenderText(child)->text()); stream << str; } } }
void Text::recalcTextStyle(StyleRecalcChange change, Text* nextTextSibling) { if (RenderText* renderer = toRenderText(this->renderer())) { if (change != NoChange || needsStyleRecalc()) renderer->setStyle(document().ensureStyleResolver().styleForText(this)); if (needsStyleRecalc()) renderer->setText(dataImpl()); clearNeedsStyleRecalc(); } else if (needsStyleRecalc() || needsWhitespaceRenderer()) { reattach(); reattachWhitespaceSiblings(nextTextSibling); } }
bool Text::recalcTextStyle(StyleChange change) { if (RenderText* renderer = toRenderText(this->renderer())) { if (change != NoChange || needsStyleRecalc()) renderer->setStyle(document()->styleResolver()->styleForText(this)); if (needsStyleRecalc()) renderer->setText(dataImpl()); clearNeedsStyleRecalc(); } else if (needsStyleRecalc() || needsWhitespaceRenderer()) { reattach(); return true; } return false; }
int Paragraph::absoluteOffsetForPosition(const PositionWithAffinity& position) { DCHECK(position.renderer()); unsigned offset = 0; for (RenderObject* object = m_renderView.get(); object; object = object->nextInPreOrder()) { if (object == position.renderer()) return offset + position.offset(); if (object->isText()) { RenderText* text = toRenderText(object); offset += text->textLength(); } } DCHECK(false); return 0; }
void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData, RecalcStyleBehavior recalcStyleBehavior) { if (!inActiveDocument()) return; RenderText* textRenderer = toRenderText(renderer()); if (!textRenderer || !textRendererIsNeeded(*textRenderer->style(), *textRenderer->parent())) { lazyReattachIfAttached(); // FIXME: Editing should be updated so this is not neccesary. if (recalcStyleBehavior == DeprecatedRecalcStyleImmediatlelyForEditing) document().updateStyleIfNeeded(); return; } textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData); }
void Text::recalcTextStyle(StyleChange change) { RenderText* renderer = toRenderText(this->renderer()); if (change != NoChange && renderer) renderer->setStyle(document()->ensureStyleResolver()->styleForText(this)); if (needsStyleRecalc()) { if (renderer) renderer->setText(dataImpl()); else reattach(); } clearNeedsStyleRecalc(); }
static void updateTextStyle(Text* text, RenderStyle* parentElementStyle, Style::Change change) { RenderText* renderer = toRenderText(text->renderer()); if (change != Style::NoChange && renderer) renderer->setStyle(parentElementStyle); if (!text->needsStyleRecalc()) return; if (renderer) renderer->setText(text->dataImpl()); else text->attachText(); text->clearNeedsStyleRecalc(); }
void Text::recalcStyle(StyleChange change) { if (change != NoChange && parentNode()) { if (renderer()) renderer()->setStyle(parentNode()->renderer()->style()); } if (needsStyleRecalc()) { if (renderer()) { if (renderer()->isText()) toRenderText(renderer())->setText(dataImpl()); } else reattach(); } clearNeedsStyleRecalc(); }
void CharacterData::appendData(const String& arg, ExceptionCode&) { String newStr = m_data; newStr.append(arg); RefPtr<StringImpl> oldStr = m_data; m_data = newStr.impl(); if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) { detach(); attach(); } else if (renderer()) toRenderText(renderer())->setTextWithOffset(m_data, oldStr->length(), 0); dispatchModifiedEvent(oldStr.get()); }
bool ContainerNode::getLowerRightCorner(FloatPoint& point) const { if (!renderer()) return false; RenderObject* o = renderer(); if (!o->isInline() || o->isReplaced()) { RenderBox* box = toRenderBox(o); point = o->localToAbsolute(LayoutPoint(box->size()), UseTransforms); return true; } // find the last text/image child, to get a position while (o) { if (o->lastChild()) o = o->lastChild(); else if (o->previousSibling()) o = o->previousSibling(); else { RenderObject* prev = 0; while (!prev) { o = o->parent(); if (!o) return false; prev = o->previousSibling(); } o = prev; } ASSERT(o); if (o->isText() || o->isReplaced()) { point = FloatPoint(); if (o->isText()) { RenderText* text = toRenderText(o); IntRect linesBox = text->linesBoundingBox(); if (!linesBox.maxX() && !linesBox.maxY()) continue; point.moveBy(linesBox.maxXMaxYCorner()); } else { RenderBox* box = toRenderBox(o); point.moveBy(box->frameRect().maxXMaxYCorner()); } point = o->container()->localToAbsolute(point, UseTransforms); return true; } } return true; }
std::unique_ptr<Layout> create(RenderBlockFlow& flow) { Layout::RunVector runs; unsigned lineCount = 0; RenderText& textRenderer = toRenderText(*flow.firstChild()); ASSERT(!textRenderer.firstTextBox()); if (textRenderer.is8Bit()) createTextRuns<LChar>(runs, lineCount, flow, textRenderer); else createTextRuns<UChar>(runs, lineCount, flow, textRenderer); textRenderer.clearNeedsLayout(); return Layout::create(runs, lineCount); }
void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData) { if (!textNode.attached()) return; RenderText* textRenderer = toRenderText(textNode.renderer()); if (!textRenderer) { attachTextRenderer(textNode); return; } RenderObject* parentRenderer = NodeRenderingTraversal::parent(&textNode)->renderer(); if (!textRendererIsNeeded(textNode, *parentRenderer, *textRenderer->style())) { detachTextRenderer(textNode); attachTextRenderer(textNode); return; } textRenderer->setTextWithOffset(textNode.dataImpl(), offsetOfReplacedData, lengthOfReplacedData); }
void InsertIntoTextNodeCommand::doApply() { if (!m_node->rendererIsEditable()) return; if (document()->settings() && document()->settings()->passwordEchoEnabled()) { RenderText* renderText = toRenderText(m_node->renderer()); if (renderText && renderText->isSecure()) renderText->momentarilyRevealLastTypedCharacter(m_offset + m_text.length() - 1); } ExceptionCode ec; m_node->insertData(m_offset, m_text, ec); if (AXObjectCache::accessibilityEnabled()) document()->axObjectCache()->nodeTextChangeNotification(m_node->renderer(), AXObjectCache::AXTextInserted, m_offset, m_text.length()); }
void InsertIntoTextNodeCommand::doApply() { bool passwordEchoEnabled = document().settings() && document().settings()->passwordEchoEnabled(); if (passwordEchoEnabled) document().updateLayoutIgnorePendingStylesheets(); if (!m_node->rendererIsEditable()) return; if (passwordEchoEnabled) { RenderText* renderText = toRenderText(m_node->renderer()); if (renderText && renderText->isSecure()) renderText->momentarilyRevealLastTypedCharacter(m_offset + m_text.length() - 1); } m_node->insertData(m_offset, m_text, IGNORE_EXCEPTION, CharacterData::DeprecatedRecalcStyleImmediatlelyForEditing); }