InlineTextBox * RenderText::findInlineTextBox( int offset, int &pos, bool checkFirstLetter ) { // The text boxes point to parts of the rendertext's str string // (they don't include '\n') // Find the text box that includes the character at @p offset // and return pos, which is the position of the char in the run. // FIXME: make this use binary search? Dirk says it won't work :-( (LS) (void)checkFirstLetter; #if 0 if (checkFirstLetter && forcedMinOffset()) { // kdDebug(6040) << "checkFirstLetter: forcedMinOffset: " << forcedMinOffset() << endl; RenderFlow *firstLetter = static_cast<RenderFlow *>(previousSibling()); if (firstLetter && firstLetter->isFlow() && firstLetter->isFirstLetter()) { RenderText *letterText = static_cast<RenderText *>(firstLetter->firstChild()); //kdDebug(6040) << "lettertext: " << letterText << " minOfs: " << letterText->minOffset() << " maxOfs: " << letterText->maxOffset() << endl; if (offset >= letterText->minOffset() && offset <= letterText->maxOffset()) { InlineTextBox *result = letterText->findInlineTextBox(offset, pos, false); //kdDebug(6040) << "result: " << result << endl; if (result) return result; } } } #endif if ( m_lines.isEmpty() ) return 0L; // The text boxes don't resemble a contiguous coverage of the text, there // may be holes. Therefore, we snap to the nearest previous text box if // the given offset happens to point to such a hole. InlineTextBox* s = m_lines[0]; uint count = m_lines.count(); uint si = 0; uint nearest_idx = 0; // index of nearest text box int nearest = INT_MAX; // nearest distance //kdDebug(6040) << "s[" << si << "] m_start " << s->m_start << " m_end " << (s->m_start + s->m_len) << endl; while(!(offset >= s->m_start && offset <= s->m_start + s->m_len) && ++si < count) { int dist = offset - (s->m_start + s->m_len); //kdDebug(6040) << "dist " << dist << " nearest " << nearest << endl; if (dist >= 0 && dist <= nearest) { nearest = dist; nearest_idx = si - 1; }/*end if*/ s = m_lines[si]; //kdDebug(6040) << "s[" << si << "] m_start " << s->m_start << " m_end " << (s->m_start + s->m_len) << endl; } //kdDebug(6040) << "nearest_idx " << nearest_idx << " count " << count << endl; if (si >= count) s = m_lines[nearest_idx]; // we are now in the correct text box pos = kMin(offset - s->m_start, int( s->m_len )); //kdDebug(6040) << "offset=" << offset << " s->m_start=" << s->m_start << endl; return s; }
RenderFlow* RenderFlow::createAnonymousFlow(DOM::DocumentImpl* doc, RenderStyle* style) { RenderFlow* result; if (style->display() == INLINE) result = new (doc->renderArena()) RenderInline(doc); else result = new (doc->renderArena()) RenderBlock(doc); result->setStyle(style); return result; }
RenderFlow* RenderFlow::createFlow(DOM::NodeImpl* node, RenderStyle* style, RenderArena* arena) { RenderFlow* result; if (style->display() == INLINE) result = new (arena) RenderInline(node); else result = new (arena) RenderBlock(node); result->setStyle(style); return result; }
void RenderInline::setStyle(RenderStyle* newStyle) { RenderFlow::setStyle(newStyle); setInline(true); // Ensure that all of the split inlines pick up the new style. We // only do this if we're an inline, since we don't want to propagate // a block's style to the other inlines. // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before // and after the block share the same style, but the block doesn't // need to pass its style on to anyone else. RenderFlow* currCont = continuation(); while (currCont) { if (currCont->isInline()) { RenderFlow* nextCont = currCont->continuation(); currCont->setContinuation(0); currCont->setStyle(style()); currCont->setContinuation(nextCont); } currCont = currCont->continuation(); } m_lineHeight = -1; // Update pseudos for :before and :after now. if (!isAnonymous()) { updateBeforeAfterContent(RenderStyle::BEFORE); updateBeforeAfterContent(RenderStyle::AFTER); } }
void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) { RenderFlow::styleDidChange(diff, oldStyle); setInline(true); //Nicki Vankoughnett: this change is indicated in webkit changest 37637, //but not obviously relevant to changes to the RenderStyle class. // setHasReflection(false); // Ensure that all of the split inlines pick up the new style. We // only do this if we're an inline, since we don't want to propagate // a block's style to the other inlines. // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before // and after the block share the same style, but the block doesn't // need to pass its style on to anyone else. RenderFlow* currCont = continuation(); while (currCont) { if (currCont->isInline()) { RenderFlow* nextCont = currCont->continuation(); currCont->setContinuation(0); currCont->setStyle(style()); currCont->setContinuation(nextCont); } currCont = currCont->continuation(); } m_lineHeight = -1; // Update pseudos for :before and :after now. if (!isAnonymous()) { updateBeforeAfterContent(RenderStyle::BEFORE); updateBeforeAfterContent(RenderStyle::AFTER); } }
void RenderInline::setStyle(RenderStyle *_style) { RenderFlow::setStyle(_style); setInline(true); // Ensure that all of the split inlines pick up the new style. We // only do this if we're an inline, since we don't want to propagate // a block's style to the other inlines. // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before // and after the block share the same style, but the block doesn't // need to pass its style on to anyone else. RenderFlow *currCont = continuation(); while(currCont) { if(currCont->isInline()) { RenderFlow *nextCont = currCont->continuation(); currCont->setContinuation(0); currCont->setStyle(style()); currCont->setContinuation(nextCont); } currCont = currCont->continuation(); } if(attached()) { // Update replaced content updateReplacedContent(); // Update pseudos for ::before and ::after updatePseudoChildren(); } }
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->x() + x; int parentBlockY = cb->y() + y; for (RenderFlow* c = continuation(); c; c = c->continuation()) { RenderFlow* contBlock = c; if (c->isInline()) contBlock = c->containingBlock(); if (c->isInline() || c->firstChild()) return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y()); } return RenderFlow::positionForCoordinates(x, y); }
void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject) { // All boxes start off open. They will not apply any margins/border/padding on // any side. bool includeLeftEdge = false; bool includeRightEdge = false; RenderFlow* flow = static_cast<RenderFlow*>(object()); if (!flow->firstChild()) includeLeftEdge = includeRightEdge = true; // Empty inlines never split across lines. else if (parent()) { // The root inline box never has borders/margins/padding. bool ltr = flow->style()->direction() == LTR; // Check to see if all initial lines are unconstructed. If so, then // we know the inline began on this line. if (!flow->firstLineBox()->isConstructed()) { if (ltr && flow->firstLineBox() == this) includeLeftEdge = true; else if (!ltr && flow->lastLineBox() == this) includeRightEdge = true; } // In order to determine if the inline ends on this line, we check three things: // (1) If we are the last line and we don't have a continuation(), then we can // close up. // (2) If the last line box for the flow has an object following it on the line (ltr, // reverse for rtl), then the inline has closed. // (3) The line may end on the inline. If we are the last child (climbing up // the end object's chain), then we just closed as well. if (!flow->lastLineBox()->isConstructed()) { if (ltr) { if (!nextLineBox() && ((lastLine && !object()->continuation()) || nextOnLineExists() || onEndChain(endObject))) includeRightEdge = true; } else { if ((!prevLineBox() || !prevLineBox()->isConstructed()) && ((lastLine && !object()->continuation()) || prevOnLineExists() || onEndChain(endObject))) includeLeftEdge = true; } } } setEdges(includeLeftEdge, includeRightEdge); // Recur into our children. for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) { if (currChild->isInlineFlowBox()) { InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild); currFlow->determineSpacingForFlowBoxes(lastLine, endObject); } } }
long CharacterDataImpl::minOffset() const { RenderText *r = static_cast<RenderText *>(renderer()); if (!r || !r->isText()) return 0; // take :first-letter into consideration #ifdef __GNUC__ #warning FIXME #endif #if 0 if (r->forcedMinOffset()) { RenderFlow *firstLetter = static_cast<RenderFlow *>(r->previousSibling()); if (firstLetter && firstLetter->isFlow() && firstLetter->isFirstLetter()) { RenderText *letterText = static_cast<RenderText *>(firstLetter->firstChild()); return letterText->minOffset(); } } #endif return r->minOffset(); }
RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild) { if (beforeChild && beforeChild->parent() == this) return this; RenderFlow* curr = continuation(); RenderFlow* nextToLast = this; RenderFlow* last = this; while (curr) { if (beforeChild && beforeChild->parent() == curr) { if (curr->firstChild() == beforeChild) return last; return curr; } nextToLast = last; last = curr; curr = curr->continuation(); } if (!beforeChild && !last->firstChild()) return nextToLast; return last; }
void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, RenderObject* beforeChild, RenderFlow* oldCont) { // Create a clone of this inline. RenderInline* clone = cloneInline(this); clone->setContinuation(oldCont); // Now take all of the children from beforeChild to the end and remove // them from |this| and place them in the clone. RenderObject* o = beforeChild; while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); clone->addChildToFlow(removeChildNode(tmp), 0); tmp->setNeedsLayoutAndPrefWidthsRecalc(); } // Hook |clone| up as the continuation of the middle block. middleBlock->setContinuation(clone); // We have been reparented and are now under the fromBlock. We need // to walk up our inline parent chain until we hit the containing block. // Once we hit the containing block we're done. RenderFlow* curr = static_cast<RenderFlow*>(parent()); RenderFlow* currChild = this; // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone. // There will eventually be a better approach to this problem that will let us nest to a much // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in // incorrect rendering, but the alternative is to hang forever. unsigned splitDepth = 1; const unsigned cMaxSplitDepth = 200; while (curr && curr != fromBlock) { if (splitDepth < cMaxSplitDepth) { // Create a new clone. RenderInline* cloneChild = clone; clone = cloneInline(curr); // Insert our child clone as the first child. clone->addChildToFlow(cloneChild, 0); // Hook the clone up as a continuation of |curr|. RenderFlow* oldCont = curr->continuation(); curr->setContinuation(clone); clone->setContinuation(oldCont); // Someone may have indirectly caused a <q> to split. When this happens, the :after content // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after // content gets properly destroyed. curr->updateBeforeAfterContent(RenderStyle::AFTER); // Now we need to take all of the children starting from the first child // *after* currChild and append them all to the clone. o = currChild->nextSibling(); while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); clone->addChildToFlow(curr->removeChildNode(tmp), 0); tmp->setNeedsLayoutAndPrefWidthsRecalc(); } } // Keep walking up the chain. currChild = curr; curr = static_cast<RenderFlow*>(curr->parent()); splitDepth++; } // Now we are at the block level. We need to put the clone into the toBlock. toBlock->appendChildNode(clone); // Now take all the children after currChild and remove them from the fromBlock // and put them in the toBlock. o = currChild->nextSibling(); while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); toBlock->appendChildNode(fromBlock->removeChildNode(tmp)); } }
void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild) { RenderFlow* flow = continuationBefore(beforeChild); KHTMLAssert(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline()); RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) : (flow->continuation() ? flow->continuation() : flow); if (newChild->isFloatingOrPositioned()) return beforeChildParent->addChildToFlow(newChild, beforeChild); // A continuation always consists of two potential candidates: an inline or an anonymous // block box holding block children. bool childInline = newChild->isInline(); bool bcpInline = beforeChildParent->isInline(); bool flowInline = flow->isInline(); if (flow == beforeChildParent) return flow->addChildToFlow(newChild, beforeChild); else { // The goal here is to match up if we can, so that we can coalesce and create the // minimal # of continuations needed for the inline. if (childInline == bcpInline) return beforeChildParent->addChildToFlow(newChild, beforeChild); else if (flowInline == childInline) return flow->addChildToFlow(newChild, 0); // Just treat like an append. else return beforeChildParent->addChildToFlow(newChild, beforeChild); } }
void RenderInline::splitInlines(RenderBlock *fromBlock, RenderBlock *toBlock, RenderBlock *middleBlock, RenderObject *beforeChild, RenderFlow *oldCont) { // Create a clone of this inline. RenderInline *clone = cloneInline(this); clone->setContinuation(oldCont); // Now take all of the children from beforeChild to the end and remove // then from |this| and place them in the clone. RenderObject *o = beforeChild; while(o) { RenderObject *tmp = o; o = tmp->nextSibling(); clone->addChildToFlow(removeChildNode(tmp), 0); tmp->setNeedsLayoutAndMinMaxRecalc(); } // Hook |clone| up as the continuation of the middle block. middleBlock->setContinuation(clone); // We have been reparented and are now under the fromBlock. We need // to walk up our inline parent chain until we hit the containing block. // Once we hit the containing block we're done. RenderFlow *curr = static_cast< RenderFlow * >(parent()); RenderFlow *currChild = this; while(curr && curr != fromBlock) { // Create a new clone. RenderInline *cloneChild = clone; clone = cloneInline(curr); // Insert our child clone as the first child. clone->addChildToFlow(cloneChild, 0); // Hook the clone up as a continuation of |curr|. RenderFlow *oldCont = curr->continuation(); curr->setContinuation(clone); clone->setContinuation(oldCont); // Now we need to take all of the children starting from the first child // *after* currChild and append them all to the clone. o = currChild->nextSibling(); while(o) { RenderObject *tmp = o; o = tmp->nextSibling(); clone->appendChildNode(curr->removeChildNode(tmp)); tmp->setNeedsLayoutAndMinMaxRecalc(); } // Keep walking up the chain. currChild = curr; curr = static_cast< RenderFlow * >(curr->parent()); } // Now we are at the block level. We need to put the clone into the toBlock. toBlock->appendChildNode(clone); // Now take all the children after currChild and remove them from the fromBlock // and put them in the toBlock. o = currChild->nextSibling(); while(o) { RenderObject *tmp = o; o = tmp->nextSibling(); toBlock->appendChildNode(fromBlock->removeChildNode(tmp)); } }