📄 svgrootinlinebox.cpp
字号:
if (chunk.isVerticalText) curChar.y += (chunkIt - chunk.start) * spacingToApply; else curChar.x += (chunkIt - chunk.start) * spacingToApply; } }}void SVGRootInlineBox::computePerCharacterLayoutInformation(){ // Clean up any previous layout information m_svgChars.clear(); m_svgTextChunks.clear(); // Build layout information for all contained render objects SVGCharacterLayoutInfo info(m_svgChars); buildLayoutInformation(this, info); // Now all layout information are available for every character // contained in any of our child inline/flow boxes. Build list // of text chunks now, to be able to apply text-anchor shifts. buildTextChunks(m_svgChars, m_svgTextChunks, this); // Layout all text chunks // text-anchor needs to be applied to individual chunks. layoutTextChunks(); // Finally the top left position of our box is known. // Propogate this knownledge to our RenderSVGText parent. FloatPoint topLeft = topLeftPositionOfCharacterRange(m_svgChars); block()->setLocation((int) floorf(topLeft.x()), (int) floorf(topLeft.y())); // Layout all InlineText/Flow boxes // BEWARE: This requires the root top/left position to be set correctly before! layoutInlineBoxes();}void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo& info){ if (start->isRootInlineBox()) { ASSERT(start->renderer()->node()->hasTagName(SVGNames::textTag)); SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(start->renderer()->node()); ASSERT(positioningElement); ASSERT(positioningElement->parentNode()); info.addLayoutInformation(positioningElement); } LastGlyphInfo lastGlyph; for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText()) buildLayoutInformationForTextBox(info, static_cast<InlineTextBox*>(curr), lastGlyph); else { ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); if (!flowBox->renderer()->node()) continue; // Skip generated content. bool isAnchor = flowBox->renderer()->node()->hasTagName(SVGNames::aTag); bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag); if (!isTextPath && !isAnchor) { SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(flowBox->renderer()->node()); ASSERT(positioningElement); ASSERT(positioningElement->parentNode()); info.addLayoutInformation(positioningElement); } else if (!isAnchor) { info.setInPathLayout(true); // Handle text-anchor/textLength on path, which is special. SVGTextContentElement* textContent = 0; Node* node = flowBox->renderer()->node(); if (node && node->isSVGElement()) textContent = static_cast<SVGTextContentElement*>(node); ASSERT(textContent); ELengthAdjust lengthAdjust = (ELengthAdjust) textContent->lengthAdjust(); ETextAnchor anchor = flowBox->renderer()->style()->svgStyle()->textAnchor(); float textAnchorStartOffset = 0.0f; // Initialize sub-layout. We need to create text chunks from the textPath // children using our standard layout code, to be able to measure the // text length using our normal methods and not textPath specific hacks. Vector<SVGChar> tempChars; Vector<SVGTextChunk> tempChunks; SVGCharacterLayoutInfo tempInfo(tempChars); buildLayoutInformation(flowBox, tempInfo); buildTextChunks(tempChars, tempChunks, flowBox); Vector<SVGTextChunk>::iterator it = tempChunks.begin(); Vector<SVGTextChunk>::iterator end = tempChunks.end(); TransformationMatrix ctm; float computedLength = 0.0f; for (; it != end; ++it) { SVGTextChunk& chunk = *it; // Apply text-length calculation info.pathExtraAdvance += calculateTextLengthCorrectionForTextChunk(chunk, lengthAdjust, computedLength); if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) { info.pathTextLength += computedLength; info.pathChunkLength += chunk.textLength; } // Calculate text-anchor start offset if (anchor == TA_START) continue; textAnchorStartOffset += calculateTextAnchorShiftForTextChunk(chunk, anchor); } info.addLayoutInformation(flowBox, textAnchorStartOffset); } float shiftxSaved = info.shiftx; float shiftySaved = info.shifty; buildLayoutInformation(flowBox, info); info.processedChunk(shiftxSaved, shiftySaved); if (isTextPath) info.setInPathLayout(false); } }}void SVGRootInlineBox::layoutInlineBoxes(){ int lowX = INT_MAX; int lowY = INT_MAX; int highX = INT_MIN; int highY = INT_MIN; // Layout all child boxes Vector<SVGChar>::iterator it = m_svgChars.begin(); layoutInlineBoxes(this, it, lowX, highX, lowY, highY); ASSERT(it == m_svgChars.end());}void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::iterator& it, int& lowX, int& highX, int& lowY, int& highY){ for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { RenderStyle* style = curr->renderer()->style(); if (curr->renderer()->isText()) { SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(curr); unsigned length = textBox->len(); SVGChar curChar = *it; ASSERT(it != m_svgChars.end()); FloatRect stringRect; for (unsigned i = 0; i < length; ++i) { ASSERT(it != m_svgChars.end()); if (it->isHidden()) { ++it; continue; } stringRect.unite(textBox->calculateGlyphBoundaries(style, textBox->start() + i, *it)); ++it; } IntRect enclosedStringRect = enclosingIntRect(stringRect); int minX = enclosedStringRect.x(); int maxX = minX + enclosedStringRect.width(); int minY = enclosedStringRect.y(); int maxY = minY + enclosedStringRect.height(); curr->setX(minX - block()->x()); curr->setWidth(enclosedStringRect.width()); curr->setY(minY - block()->y()); textBox->setHeight(enclosedStringRect.height()); if (minX < lowX) lowX = minX; if (maxX > highX) highX = maxX; if (minY < lowY) lowY = minY; if (maxY > highY) highY = maxY; } else { ASSERT(curr->isInlineFlowBox()); int minX = INT_MAX; int minY = INT_MAX; int maxX = INT_MIN; int maxY = INT_MIN; InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); if (!flowBox->renderer()->node()) continue; // Skip generated content. layoutInlineBoxes(flowBox, it, minX, maxX, minY, maxY); curr->setX(minX - block()->x()); curr->setWidth(maxX - minX); curr->setY(minY - block()->y()); static_cast<SVGInlineFlowBox*>(curr)->setHeight(maxY - minY); if (minX < lowX) lowX = minX; if (maxX > highX) highX = maxX; if (minY < lowY) lowY = minY; if (maxY > highY) highY = maxY; } } if (start->isSVGRootInlineBox()) { int top = lowY - block()->y(); int bottom = highY - block()->y(); start->setX(lowX - block()->x()); start->setY(top); start->setWidth(highX - lowX); static_cast<SVGRootInlineBox*>(start)->setHeight(highY - lowY); start->setVerticalOverflowPositions(top, bottom); start->setVerticalSelectionPositions(top, bottom); }}void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& info, InlineTextBox* textBox, LastGlyphInfo& lastGlyph){ RenderText* text = textBox->textRenderer(); ASSERT(text); RenderStyle* style = text->style(textBox->isFirstLineStyle()); ASSERT(style); const Font& font = style->font(); SVGInlineTextBox* svgTextBox = static_cast<SVGInlineTextBox*>(textBox); unsigned length = textBox->len(); const SVGRenderStyle* svgStyle = style->svgStyle(); bool isVerticalText = isVerticalWritingMode(svgStyle); int charsConsumed = 0; for (unsigned i = 0; i < length; i += charsConsumed) { SVGChar svgChar; if (info.inPathLayout()) svgChar.pathData = SVGCharOnPath::create(); float glyphWidth = 0.0f; float glyphHeight = 0.0f; int extraCharsAvailable = length - i - 1; String unicodeStr; String glyphName; if (textBox->direction() == RTL) { glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i, extraCharsAvailable, charsConsumed, glyphName); glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i, extraCharsAvailable); unicodeStr = String(textBox->textRenderer()->text()->characters() + textBox->end() - i, charsConsumed); } else { glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->start() + i, extraCharsAvailable, charsConsumed, glyphName); glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->start() + i, extraCharsAvailable); unicodeStr = String(textBox->textRenderer()->text()->characters() + textBox->start() + i, charsConsumed); } bool assignedX = false; bool assignedY = false; if (info.xValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && !isVerticalText))) { if (!isVerticalText) svgChar.newTextChunk = true; assignedX = true; svgChar.drawnSeperated = true; info.curx = info.xValueNext(); } if (info.yValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && isVerticalText))) { if (isVerticalText) svgChar.newTextChunk = true; assignedY = true; svgChar.drawnSeperated = true; info.cury = info.yValueNext(); } float dx = 0.0f; float dy = 0.0f; // Apply x-axis shift if (info.dxValueAvailable()) { svgChar.drawnSeperated = true; dx = info.dxValueNext(); info.dx += dx; if (!info.inPathLayout()) info.curx += dx; } // Apply y-axis shift if (info.dyValueAvailable()) { svgChar.drawnSeperated = true; dy = info.dyValueNext(); info.dy += dy; if (!info.inPathLayout()) info.cury += dy; } // Take letter & word spacing and kerning into account float spacing = font.letterSpacing() + calculateKerning(textBox->renderer()->node()->renderer()); const UChar* currentCharacter = text->characters() + (textBox->direction() == RTL ? textBox->end() - i : textBox->start() + i); const UChar* lastCharacter = 0; if (textBox->direction() == RTL) { if (i < textBox->end()) lastCharacter = text->characters() + textBox->end() - i + 1; } else { if (i > 0) lastCharacter = text->characters() + textBox->start() + i - 1; } if (info.nextDrawnSeperated || spacing != 0.0f) { info.nextDrawnSeperated = false; svgChar.drawnSeperated = true; } if (currentCharacter && Font::treatAsSpace(*currentCharacter) && lastCharacter && !Font::treatAsSpace(*lastCharacter)) { spacing += font.wordSpacing(); if (spacing != 0.0f && !info.inPathLayout()) info.nextDrawnSeperated = true; } float orientationAngle = glyphOrientationToAngle(svgStyle, isVerticalText, *currentCharacter); float xOrientationShift = 0.0f; float yOrientationShift = 0.0f; float glyphAdvance = calculateGlyphAdvanceAndShiftRespectingOrientation(isVerticalText, orientationAngle, glyphWidth, glyphHeight, font, svgChar, xOrientationShift, yOrientationShift); // Handle textPath layout mode if (info.inPathLayout()) { float extraAdvance = isVerticalText ? dy : dx; float newOffset = FLT_MIN; if (assignedX && !isVerticalText) newOffset = info.curx; else if (assignedY && isVerticalText) newOffset = info.cury; float correctedGlyphAdvance = glyphAdvance; // Handle lengthAdjust="spacingAndGlyphs" by specifying per-character scale operations if (info.pathTextLength > 0.0f && info.pathChunkLength > 0.0f) { if (isVerticalText) { svgChar.pathData->yScale = info.pathChunkLength / info.pathTextLength; spacing *= svgChar.pathData->yScale; correctedGlyphAdvance *= svgChar.pathData->yScale; } else { svgChar.pathData->xScale = info.pathChunkLength / info.pathTextLength; spacing *= svgChar.pathData->xScale; correctedGlyphAdvance *= svgChar.pathData->xScale; } } // Handle letter & word spacing on text path float pathExtraAdvance = info.pathExtraAdvance; info.pathExtraAdvance += spacing; svgChar.pathData->hidden = !info.nextPathLayoutPointAndAngle(correctedGlyphAdvance, extraAdvance, newOffset); svgChar.drawnSeperated = true; info.pathExtraAdvance = pathExtraAdvance; } // Apply rotation if (info.angleValueAvailable()) info.angle = info.angleValueNext(); // Apply baseline-shift if (info.baselineShiftValueAvailable()) { svgChar.drawnSeperated = true; float shift = info.baselineShiftValueNext(); if (isVerticalText) info.shiftx += shift; else info.shifty -= shift; } // Take dominant-baseline / alignment-baseline into account yOrientationShift += alignmentBaselineToShift(isVerticalText, text, font); svgChar.x = info.curx; svgChar.y = info.cury; svgChar.angle = info.angle; // For text paths any shift (dx/dy/baseline-shift) has to be applied after the rotation if (!info.inPathLayout()) { svgChar.x += info.shiftx + xOrientationShift; svgChar.y += info.shifty + yOrientationShift; if (orientationAngle != 0.0f)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -