📄 bidi.cpp
字号:
else if (!last) last = curr; } } if (!last) return 0; RootInlineBox* prev = last->prevRootBox(); cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos()); cleanLineBidiStatus = prev->lineBreakBidiStatus(); yPos = prev->blockHeight(); for (RootInlineBox* line = last; line; line = line->nextRootBox()) line->extractLine(); // Disconnect all line boxes from their render objects while preserving // their connections to one another. return last;}bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop){ if (resolver.position() == endLineStart) { if (resolver.status() != endLineStatus) return false; int delta = height() - endYPos; if (!delta || !m_floatingObjects) return true; // See if any floats end in the range along which we want to shift the lines vertically. int top = min(height(), endYPos); RootInlineBox* lastLine = endLine; while (RootInlineBox* nextLine = lastLine->nextRootBox()) lastLine = nextLine; int bottom = lastLine->blockHeight() + abs(delta); for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { if (f->m_bottom >= top && f->m_bottom < bottom) return false; } return true; } // The first clean line doesn't match, but we can check a handful of following lines to try // to match back up. static int numLines = 8; // The # of lines we're willing to match against. RootInlineBox* line = endLine; for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) { if (line->lineBreakObj() == resolver.position().obj && line->lineBreakPos() == resolver.position().pos) { // We have a match. if (line->lineBreakBidiStatus() != resolver.status()) return false; // ...but the bidi state doesn't match. RootInlineBox* result = line->nextRootBox(); // Set our yPos to be the block height of endLine. if (result) endYPos = line->blockHeight(); int delta = height() - endYPos; if (delta && m_floatingObjects) { // See if any floats end in the range along which we want to shift the lines vertically. int top = min(height(), endYPos); RootInlineBox* lastLine = endLine; while (RootInlineBox* nextLine = lastLine->nextRootBox()) lastLine = nextLine; int bottom = lastLine->blockHeight() + abs(delta); for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { if (f->m_bottom >= top && f->m_bottom < bottom) return false; } } // Now delete the lines that we failed to sync. RootInlineBox* boxToDelete = endLine; RenderArena* arena = renderArena(); while (boxToDelete && boxToDelete != result) { repaintTop = min(repaintTop, boxToDelete->topOverflow()); repaintBottom = max(repaintBottom, boxToDelete->bottomOverflow()); RootInlineBox* next = boxToDelete->nextRootBox(); boxToDelete->deleteLine(arena); boxToDelete = next; } endLine = result; return result; } } return false;}static inline bool skipNonBreakingSpace(const InlineIterator& it){ if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace) return false; // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly // with m_minWidth/m_maxWidth. // Do not skip a non-breaking space if it is the first character // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off // |true|). if (isLineEmpty && previousLineBrokeCleanly) return false; return true;}static inline bool shouldCollapseWhiteSpace(const RenderStyle* style){ return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly));}static inline bool shouldPreserveNewline(RenderObject* object){#if ENABLE(SVG) if (object->isSVGText()) return false;#endif return object->style()->preserveNewline();}static bool inlineFlowRequiresLineBox(RenderInline* flow){ // FIXME: Right now, we only allow line boxes for inlines that are truly empty. // We need to fix this, though, because at the very least, inlines containing only // ignorable whitespace should should also have line boxes. return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin();}static inline bool requiresLineBox(const InlineIterator& it){ if (it.obj->isFloatingOrPositioned()) return false; if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.obj))) return false; if (!shouldCollapseWhiteSpace(it.obj->style()) || it.obj->isBR()) return true; UChar current = it.current(); return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj)) && !skipNonBreakingSpace(it);}bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj){ ASSERT(inlineObj->parent() == this); InlineIterator it(this, inlineObj, 0); while (!it.atEnd() && !requiresLineBox(it)) it.increment(); return !it.atEnd();}// FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned// elements quite right. In other words, we need to build this function's work into the normal line// object iteration process.// NB. this function will insert any floating elements that would otherwise// be skipped but it will not position them.void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator){ while (!iterator.atEnd() && !requiresLineBox(iterator)) { RenderObject* object = iterator.obj; if (object->isFloating()) { insertFloatingObject(toRenderBox(object)); } else if (object->isPositioned()) { // FIXME: The math here is actually not really right. It's a best-guess approximation that // will work for the common cases RenderObject* c = object->container(); if (c->isRenderInline()) { // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned // inline so that we can obtain the value later. toRenderInline(c)->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), false) : rightOffset(height(), false)); toRenderInline(c)->layer()->setStaticY(height()); } RenderBox* box = toRenderBox(object); if (box->style()->hasStaticX()) { if (box->style()->isOriginalDisplayInlineType()) box->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), false) : width() - rightOffset(height(), false)); else box->layer()->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); } if (box->style()->hasStaticY()) box->layer()->setStaticY(height()); } iterator.increment(); }}int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine){ int availableWidth = lineWidth(height(), firstLine); while (!resolver.position().atEnd() && !requiresLineBox(resolver.position())) { RenderObject* object = resolver.position().obj; if (object->isFloating()) { insertFloatingObject(toRenderBox(object)); positionNewFloats(); availableWidth = lineWidth(height(), firstLine); } else if (object->isPositioned()) { // FIXME: The math here is actually not really right. It's a best-guess approximation that // will work for the common cases RenderObject* c = object->container(); if (c->isRenderInline()) { // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned // inline so that we can obtain the value later. toRenderInline(c)->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), firstLine) : rightOffset(height(), firstLine)); toRenderInline(c)->layer()->setStaticY(height()); } RenderBox* box = toRenderBox(object); if (box->style()->hasStaticX()) { if (box->style()->isOriginalDisplayInlineType()) box->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), firstLine) : width() - rightOffset(height(), firstLine)); else box->layer()->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); } if (box->style()->hasStaticY()) box->layer()->setStaticY(height()); } resolver.increment(); } resolver.commitExplicitEmbedding(); return availableWidth;}// This is currently just used for list markers and inline flows that have line boxes. Neither should // have an effect on whitespace at the start of the line. static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o){ RenderObject* next = bidiNext(block, o); if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) { RenderText* nextText = toRenderText(next); UChar nextChar = nextText->characters()[0]; if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) { addMidpoint(InlineIterator(0, o, 0)); return true; } } return false;}void RenderBlock::fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth){ ASSERT(widthToFit > availableWidth); int floatBottom; int lastFloatBottom = height(); int newLineWidth = availableWidth; while (true) { floatBottom = nextFloatBottomBelow(lastFloatBottom); if (!floatBottom) break; newLineWidth = lineWidth(floatBottom, firstLine); lastFloatBottom = floatBottom; if (newLineWidth >= widthToFit) break; } if (newLineWidth > availableWidth) { setHeight(lastFloatBottom); availableWidth = newLineWidth; }}static inline unsigned textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, int xPos, bool isFixedPitch, bool collapseWhiteSpace){ if (isFixedPitch || !from && len == text->textLength()) return text->width(from, len, font, xPos); return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos));}InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, EClear* clear){ ASSERT(resolver.position().block == this); bool appliedStartWidth = resolver.position().pos > 0; int width = skipLeadingWhitespace(resolver, firstLine); int w = 0; int tmpW = 0; if (resolver.position().atEnd()) return resolver.position(); // This variable is used only if whitespace isn't set to PRE, and it tells us whether // or not we are currently ignoring whitespace. bool ignoringSpaces = false; InlineIterator ignoreStart; // This variable tracks whether the very last character we saw was a space. We use // this to detect when we encounter a second space so we know we have to terminate // a run. bool currentCharacterIsSpace = false; bool currentCharacterIsWS = false; RenderObject* trailingSpaceObject = 0; InlineIterator lBreak = resolver.position(); RenderObject *o =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -