📄 bidi.cpp
字号:
if (obj && obj->isListMarker()) return obj->style()->direction() == LTR ? LeftToRight : RightToLeft; return OtherNeutral;}// -------------------------------------------------------------------------------------------------static void chopMidpointsAt(RenderObject* obj, unsigned pos){ if (!sNumMidpoints) return; InlineIterator* midpoints = smidpoints->data(); for (int i = sNumMidpoints - 1; i >= 0; i--) { const InlineIterator& point = midpoints[i]; if (point.obj == obj && point.pos == pos) { sNumMidpoints = i; break; } }}static void checkMidpoints(InlineIterator& lBreak){ // Check to see if our last midpoint is a start point beyond the line break. If so, // shave it off the list, and shave off a trailing space if the previous end point doesn't // preserve whitespace. if (lBreak.obj && sNumMidpoints && sNumMidpoints % 2 == 0) { InlineIterator* midpoints = smidpoints->data(); InlineIterator& endpoint = midpoints[sNumMidpoints-2]; const InlineIterator& startpoint = midpoints[sNumMidpoints-1]; InlineIterator currpoint = endpoint; while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) currpoint.increment(); if (currpoint == lBreak) { // We hit the line break before the start point. Shave off the start point. sNumMidpoints--; if (endpoint.obj->style()->collapseWhiteSpace()) { if (endpoint.obj->isText()) { // Don't shave a character off the endpoint if it was from a soft hyphen. RenderText* textObj = toRenderText(endpoint.obj); if (endpoint.pos + 1 < textObj->textLength()) { if (textObj->characters()[endpoint.pos+1] == softHyphen) return; } else if (startpoint.obj->isText()) { RenderText *startText = toRenderText(startpoint.obj); if (startText->textLength() && startText->characters()[0] == softHyphen) return; } } endpoint.pos--; } } } }static void addMidpoint(const InlineIterator& midpoint){ if (smidpoints->size() <= sNumMidpoints) smidpoints->grow(sNumMidpoints + 10); InlineIterator* midpoints = smidpoints->data(); midpoints[sNumMidpoints++] = midpoint;}static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver){ if (start > end || obj->isFloating() || (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline())) return; bool haveNextMidpoint = (sCurrMidpoint < sNumMidpoints); InlineIterator nextMidpoint; if (haveNextMidpoint) nextMidpoint = smidpoints->at(sCurrMidpoint); if (betweenMidpoints) { if (!(haveNextMidpoint && nextMidpoint.obj == obj)) return; // This is a new start point. Stop ignoring objects and // adjust our start. betweenMidpoints = false; start = nextMidpoint.pos; sCurrMidpoint++; if (start < end) return appendRunsForObject(start, end, obj, resolver); } else { if (!haveNextMidpoint || (obj != nextMidpoint.obj)) { resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir())); return; } // An end midpoint has been encountered within our object. We // need to go ahead and append a run with our endpoint. if (static_cast<int>(nextMidpoint.pos + 1) <= end) { betweenMidpoints = true; sCurrMidpoint++; if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it. if (static_cast<int>(nextMidpoint.pos + 1) > start) resolver.addRun(new (obj->renderArena()) BidiRun(start, nextMidpoint.pos + 1, obj, resolver.context(), resolver.dir())); return appendRunsForObject(nextMidpoint.pos + 1, end, obj, resolver); } } else resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir())); }}template <>void InlineBidiResolver::appendRun(){ if (!emptyRun && !eor.atEnd()) { int start = sor.pos; RenderObject *obj = sor.obj; while (obj && obj != eor.obj && obj != endOfLine.obj) { appendRunsForObject(start, obj->length(), obj, *this); start = 0; obj = bidiNext(sor.block, obj); } if (obj) { unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX; if (obj == endOfLine.obj && endOfLine.pos <= pos) { reachedEndOfLine = true; pos = endOfLine.pos; } // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be int end = obj->length() ? pos+1 : 0; appendRunsForObject(start, end, obj, *this); } eor.increment(); sor = eor; } m_direction = OtherNeutral; m_status.eor = OtherNeutral;}static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false){ if (isRootLineBox) return toRenderBlock(obj)->createRootInlineBox(); if (obj->isText()) { InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox(); // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.) if (obj->isBR()) textBox->setIsText(isOnlyRun || obj->document()->inStrictMode()); return textBox; } if (obj->isBox()) return toRenderBox(obj)->createInlineBox(); return toRenderInline(obj)->createInlineFlowBox();}static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout){ if (o->isText()) { if (o->prefWidthsDirty() && o->isCounter()) toRenderText(o)->calcPrefWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed. toRenderText(o)->dirtyLineBoxes(fullLayout); } else toRenderInline(o)->dirtyLineBoxes(fullLayout);}InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine){ // See if we have an unconstructed line box for this object that is also // the last item on the line. unsigned lineDepth = 1; InlineFlowBox* childBox = 0; InlineFlowBox* parentBox = 0; InlineFlowBox* result = 0; do { ASSERT(obj->isRenderInline() || obj == this); // Get the last box we made for this render object. parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox(); // If this box is constructed then it is from a previous line, and we need // to make a new box for our line. If this box is unconstructed but it has // something following it on the line, then we know we have to make a new box // as well. In this situation our inline has actually been split in two on // the same line (this can happen with very fancy language mixtures). bool constructedNewBox = false; if (!parentBox || parentBox->isConstructed() || parentBox->nextOnLine()) { // We need to make a new box for this render object. Once // made, we need to place it at the end of the current line. InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this); ASSERT(newBox->isInlineFlowBox()); parentBox = static_cast<InlineFlowBox*>(newBox); parentBox->setFirstLineStyleBit(firstLine); constructedNewBox = true; } if (!result) result = parentBox; // If we have hit the block itself, then |box| represents the root // inline box for the line, and it doesn't have to be appended to any parent // inline. if (childBox) parentBox->addToLine(childBox); if (!constructedNewBox || obj == this) break; childBox = parentBox; // If we've exceeded our line depth, then jump straight to the root and skip all the remaining // intermediate inline flows. obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent(); } while (true); return result;}RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject){ ASSERT(firstRun); InlineFlowBox* parentBox = 0; for (BidiRun* r = firstRun; r; r = r->next()) { // Create a box for our object. bool isOnlyRun = (runCount == 1); if (runCount == 2 && !r->m_object->isListMarker()) isOnlyRun = ((style()->direction() == RTL) ? lastRun : firstRun)->m_object->isListMarker(); InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun); r->m_box = box; if (box) { // If we have no parent box yet, or if the run is not simply a sibling, // then we need to construct inline boxes as necessary to properly enclose the // run's inline box. if (!parentBox || parentBox->renderer() != r->m_object->parent()) // Create new inline boxes all the way back to the appropriate insertion point. parentBox = createLineBoxes(r->m_object->parent(), firstLine); // Append the inline box to this line. parentBox->addToLine(box); bool visuallyOrdered = r->m_object->style()->visuallyOrdered(); box->setBidiLevel(visuallyOrdered ? 0 : r->level()); if (box->isInlineTextBox()) { InlineTextBox* text = static_cast<InlineTextBox*>(box); text->setStart(r->m_start); text->setLen(r->m_stop - r->m_start); text->m_dirOverride = r->dirOverride(visuallyOrdered); } } } // We should have a root inline box. It should be unconstructed and // be the last continuation of our line list. ASSERT(lastLineBox() && !lastLineBox()->isConstructed()); // Set bits on our inline flow boxes that indicate which sides should // paint borders/margins/padding. This knowledge will ultimately be used when // we determine the horizontal positions and widths of all the inline boxes on // the line. lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject); // Now mark the line boxes as being constructed. lastLineBox()->setConstructed(); // Return the last line. return lastRootBox();}void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd){ // First determine our total width. int availableWidth = lineWidth(height(), firstLine); int totWidth = lineBox->getFlowSpacingWidth(); bool needsWordSpacing = false; unsigned numSpaces = 0; ETextAlign textAlign = style()->textAlign(); for (BidiRun* r = firstRun; r; r = r->next()) { if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak()) continue; // Positioned objects are only participating to figure out their // correct static x position. They have no effect on the width. // Similarly, line break boxes have no effect on the width. if (r->m_object->isText()) { RenderText* rt = toRenderText(r->m_object); if (textAlign == JUSTIFY && r != trailingSpaceRun) { const UChar* characters = rt->characters(); for (int i = r->m_start; i < r->m_stop; i++) { UChar c = characters[i]; if (c == ' ' || c == '\n' || c == '\t') numSpaces++; } } if (int length = rt->textLength()) { if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start])) totWidth += rt->style(firstLine)->font().wordSpacing(); needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length; } r->m_box->setWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, firstLine)); } else if (!r->m_object->isRenderInline()) { RenderBox* renderBox = toRenderBox(r->m_object); renderBox->calcWidth(); r->m_box->setWidth(renderBox->width()); totWidth += renderBox->marginLeft() + renderBox->marginRight(); } totWidth += r->m_box->width(); } // Armed with the total width of the line (without justification), // we now examine our text-align property in order to determine where to position the // objects horizontally. The total width of the line can be increased if we end up // justifying text. int x = leftOffset(height(), firstLine);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -