📄 bidi.cpp
字号:
switch(textAlign) { case LEFT: case WEBKIT_LEFT: // The direction of the block should determine what happens with wide lines. In // particular with RTL blocks, wide lines should still spill out to the left. if (style()->direction() == LTR) { if (totWidth > availableWidth && trailingSpaceRun) trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth); } else { if (trailingSpaceRun) trailingSpaceRun->m_box->setWidth(0); else if (totWidth > availableWidth) x -= (totWidth - availableWidth); } break; case JUSTIFY: if (numSpaces && !reachedEnd && !lineBox->endsWithBreak()) { if (trailingSpaceRun) { totWidth -= trailingSpaceRun->m_box->width(); trailingSpaceRun->m_box->setWidth(0); } break; } // fall through case TAAUTO: numSpaces = 0; // for right to left fall through to right aligned if (style()->direction() == LTR) { if (totWidth > availableWidth && trailingSpaceRun) trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth); break; } case RIGHT: case WEBKIT_RIGHT: // Wide lines spill out of the block based off direction. // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right // side of the block. if (style()->direction() == LTR) { if (trailingSpaceRun) { totWidth -= trailingSpaceRun->m_box->width(); trailingSpaceRun->m_box->setWidth(0); } if (totWidth < availableWidth) x += availableWidth - totWidth; } else { if (totWidth > availableWidth && trailingSpaceRun) { trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth); totWidth -= trailingSpaceRun->m_box->width(); } else x += availableWidth - totWidth; } break; case CENTER: case WEBKIT_CENTER: int trailingSpaceWidth = 0; if (trailingSpaceRun) { totWidth -= trailingSpaceRun->m_box->width(); trailingSpaceWidth = min(trailingSpaceRun->m_box->width(), (availableWidth - totWidth + 1) / 2); trailingSpaceRun->m_box->setWidth(trailingSpaceWidth); } if (style()->direction() == LTR) x += max((availableWidth - totWidth) / 2, 0); else x += totWidth > availableWidth ? (availableWidth - totWidth) : (availableWidth - totWidth) / 2 - trailingSpaceWidth; break; } if (numSpaces) { for (BidiRun* r = firstRun; r; r = r->next()) { if (!r->m_box || r == trailingSpaceRun) continue; int spaceAdd = 0; if (r->m_object->isText()) { unsigned spaces = 0; const UChar* characters = toRenderText(r->m_object)->characters(); for (int i = r->m_start; i < r->m_stop; i++) { UChar c = characters[i]; if (c == ' ' || c == '\n' || c == '\t') spaces++; } ASSERT(spaces <= numSpaces); // Only justify text if whitespace is collapsed. if (r->m_object->style()->collapseWhiteSpace()) { spaceAdd = (availableWidth - totWidth) * spaces / numSpaces; static_cast<InlineTextBox*>(r->m_box)->setSpaceAdd(spaceAdd); totWidth += spaceAdd; } numSpaces -= spaces; if (!numSpaces) break; } } } // The widths of all runs are now known. We can now place every inline box (and // compute accurate widths for the inline flow boxes). int leftPosition = x; int rightPosition = x; needsWordSpacing = false; lineBox->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing); lineBox->setHorizontalOverflowPositions(leftPosition, rightPosition);}void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun){ setHeight(lineBox->verticallyAlignBoxes(height())); lineBox->setBlockHeight(height()); // See if the line spilled out. If so set overflow height accordingly. int bottomOfLine = lineBox->bottomOverflow(); if (bottomOfLine > height() && bottomOfLine > m_overflowHeight) m_overflowHeight = bottomOfLine; // Now make sure we place replaced render objects correctly. for (BidiRun* r = firstRun; r; r = r->next()) { if (!r->m_box) continue; // Skip runs with no line boxes. // Align positioned boxes with the top of the line box. This is // a reasonable approximation of an appropriate y position. if (r->m_object->isPositioned()) r->m_box->setY(height()); // Position is used to properly position both replaced elements and // to update the static normal flow x/y of positioned elements. if (r->m_object->isText()) toRenderText(r->m_object)->positionLineBox(r->m_box); else if (r->m_object->isBox()) toRenderBox(r->m_object)->positionLineBox(r->m_box); } // Positioned objects and zero-length text nodes destroy their boxes in // position(), which unnecessarily dirties the line. lineBox->markDirty(false);}// collects one line of the paragraph and transforms it to visual ordervoid RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIterator& end){ resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly);}static inline bool isCollapsibleSpace(UChar character, RenderText* renderer){ if (character == ' ' || character == '\t' || character == softHyphen) return true; if (character == '\n') return !renderer->style()->preserveNewline(); if (character == noBreakSpace) return renderer->style()->nbspMode() == SPACE; return false;}void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom){ bool useRepaintBounds = false; m_overflowHeight = 0; setHeight(borderTop() + paddingTop()); int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); // Figure out if we should clear out our line boxes. // FIXME: Handle resize eventually! // FIXME: Do something better when floats are present. bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren; if (fullLayout) lineBoxes()->deleteLineBoxes(renderArena()); // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't // clip. // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense // anyway, so we won't worry about following the draft here. bool hasTextOverflow = style()->textOverflow() && hasOverflowClip(); // Walk all the lines and delete our ellipsis line boxes if they exist. if (hasTextOverflow) deleteEllipsisLineBoxes(); if (firstChild()) { // layout replaced elements bool endOfInline = false; RenderObject* o = bidiFirst(this, 0, false); Vector<FloatWithRect> floats; while (o) { if (o->isReplaced() || o->isFloating() || o->isPositioned()) { RenderBox* box = toRenderBox(o); if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent()) o->setChildNeedsLayout(true, false); // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. if (relayoutChildren && (o->style()->paddingLeft().isPercent() || o->style()->paddingRight().isPercent())) o->setPrefWidthsDirty(true, false); if (o->isPositioned()) o->containingBlock()->insertPositionedObject(box); else { if (o->isFloating()) floats.append(FloatWithRect(box)); else if (fullLayout || o->needsLayout()) // Replaced elements toRenderBox(o)->dirtyLineBoxes(fullLayout); o->layoutIfNeeded(); } } else if (o->isText() || (o->isRenderInline() && !endOfInline)) { if (fullLayout || o->selfNeedsLayout()) dirtyLineBoxesForRenderer(o, fullLayout); o->setNeedsLayout(false); if (!o->isText()) toRenderInline(o)->invalidateVerticalPosition(); // FIXME: Should do better here and not always invalidate everything. } o = bidiNext(this, o, 0, false, &endOfInline); } // We want to skip ahead to the first dirty line InlineBidiResolver resolver; unsigned floatIndex; bool firstLine = true; RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, resolver, floats, floatIndex); if (fullLayout && !selfNeedsLayout()) { setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like // we're supposed to. RenderView* v = view(); if (v && !v->doingFullRepaint() && hasLayer()) { // Because we waited until we were already inside layout to discover // that the block really needed a full layout, we missed our chance to repaint the layer // before layout started. Luckily the layer has cached the repaint rect for its original // position and size, and so we can use that to make a repaint happen now. repaintUsingContainer(containerForRepaint(), layer()->repaintRect()); } } FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0; if (!smidpoints) smidpoints = new Vector<InlineIterator>(); sNumMidpoints = 0; sCurrMidpoint = 0; // We also find the first clean line and extract these lines. We will add them back // if we determine that we're able to synchronize after handling all our dirty lines. InlineIterator cleanLineStart; BidiStatus cleanLineBidiStatus; int endLineYPos = 0; RootInlineBox* endLine = (fullLayout || !startLine) ? 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos); if (startLine) { useRepaintBounds = true; repaintTop = height(); repaintBottom = height(); RenderArena* arena = renderArena(); RootInlineBox* box = startLine; while (box) { repaintTop = min(repaintTop, box->topOverflow()); repaintBottom = max(repaintBottom, box->bottomOverflow()); RootInlineBox* next = box->nextRootBox(); box->deleteLine(arena); box = next; } } InlineIterator end = resolver.position(); if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) { // If the last line before the start line ends with a line break that clear floats, // adjust the height accordingly. // A line break can be either the first or the last object on a line, depending on its direction. if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) { RenderObject* lastObject = lastLeafChild->renderer(); if (!lastObject->isBR()) lastObject = lastRootBox()->firstLeafChild()->renderer(); if (lastObject->isBR()) { EClear clear = lastObject->style()->clear(); if (clear != CNONE) newLine(clear); } } } bool endLineMatched = false; bool checkForEndLineMatch = endLine; bool checkForFloatsFromLastLine = false; int lastHeight = height(); while (!end.atEnd()) { // FIXME: Is this check necessary before the first iteration or can it be moved to the end? if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop))) break; betweenMidpoints = false; isLineEmpty = true; EClear clear = CNONE; end = findNextLineBreak(resolver, firstLine, &clear); if (resolver.position().atEnd()) { resolver.deleteRuns(); checkForFloatsFromLastLine = true; break; } ASSERT(end != resolver.position()); if (!isLineEmpty) { bidiReorderLine(resolver, end); ASSERT(resolver.position() == end); BidiRun* trailingSpaceRun = 0; if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()) { trailingSpaceRun = resolver.logicallyLastRun(); RenderObject* lastObject = trailingSpaceRun->m_object; if (lastObject->isText()) { RenderText* lastText = toRenderText(lastObject); const UChar* characters = lastText->characters(); int firstSpace = trailingSpaceRun->stop(); while (firstSpace > trailingSpaceRun->start()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -