📄 svgrootinlinebox.cpp
字号:
svgChar.angle += orientationAngle; if (svgChar.angle != 0.0f) svgChar.drawnSeperated = true; } else { svgChar.pathData->orientationAngle = orientationAngle; if (isVerticalText) svgChar.angle -= 90.0f; svgChar.pathData->xShift = info.shiftx + xOrientationShift; svgChar.pathData->yShift = info.shifty + yOrientationShift; // Translate to glyph midpoint if (isVerticalText) { svgChar.pathData->xShift += info.dx; svgChar.pathData->yShift -= glyphAdvance / 2.0f; } else { svgChar.pathData->xShift -= glyphAdvance / 2.0f; svgChar.pathData->yShift += info.dy; } } double kerning = 0.0;#if ENABLE(SVG_FONTS) SVGFontElement* svgFont = 0; if (style->font().isSVGFont()) svgFont = style->font().svgFont(); if (lastGlyph.isValid && style->font().isSVGFont()) { SVGHorizontalKerningPair kerningPair; if (svgFont->getHorizontalKerningPairForStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeStr, glyphName, kerningPair)) kerning = kerningPair.kerning; } if (style->font().isSVGFont()) { lastGlyph.unicode = unicodeStr; lastGlyph.glyphName = glyphName; lastGlyph.isValid = true; } else lastGlyph.isValid = false;#endif svgChar.x -= (float)kerning; // Advance to new position if (isVerticalText) { svgChar.drawnSeperated = true; info.cury += glyphAdvance + spacing; } else info.curx += glyphAdvance + spacing - (float)kerning; // Advance to next character group for (int k = 0; k < charsConsumed; ++k) { info.svgChars.append(svgChar); info.processedSingleCharacter(); svgChar.drawnSeperated = false; svgChar.newTextChunk = false; } }}void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, Vector<SVGTextChunk>& svgTextChunks, InlineFlowBox* start){ SVGTextChunkLayoutInfo info(svgTextChunks); info.it = svgChars.begin(); info.chunk.start = svgChars.begin(); info.chunk.end = svgChars.begin(); buildTextChunks(svgChars, start, info); ASSERT(info.it == svgChars.end());}void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* start, SVGTextChunkLayoutInfo& info){#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> buildTextChunks(start=%p)\n", start);#endif for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText()) { InlineTextBox* textBox = static_cast<InlineTextBox*>(curr); unsigned length = textBox->len(); if (!length) continue;#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Handle inline text box (%p) with %i characters (start: %i, end: %i), handlingTextPath=%i\n", textBox, length, textBox->start(), textBox->end(), (int) info.handlingTextPath);#endif RenderText* text = textBox->textRenderer(); ASSERT(text); ASSERT(text->node()); SVGTextContentElement* textContent = 0; Node* node = text->node()->parent(); while (node && node->isSVGElement() && !textContent) { if (static_cast<SVGElement*>(node)->isTextContent()) textContent = static_cast<SVGTextContentElement*>(node); else node = node->parentNode(); } ASSERT(textContent); // Start new character range for the first chunk bool isFirstCharacter = info.svgTextChunks.isEmpty() && info.chunk.start == info.it && info.chunk.start == info.chunk.end; if (isFirstCharacter) { ASSERT(info.chunk.boxes.isEmpty()); info.chunk.boxes.append(SVGInlineBoxCharacterRange()); } else ASSERT(!info.chunk.boxes.isEmpty()); // Walk string to find out new chunk positions, if existant for (unsigned i = 0; i < length; ++i) { ASSERT(info.it != svgChars.end()); SVGInlineBoxCharacterRange& range = info.chunk.boxes.last(); if (range.isOpen()) { range.box = curr; range.startOffset = (i == 0 ? 0 : i - 1);#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Range is open! box=%p, startOffset=%i\n", range.box, range.startOffset);#endif } // If a new (or the first) chunk has been started, record it's text-anchor and writing mode. if (info.assignChunkProperties) { info.assignChunkProperties = false; info.chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle()); info.chunk.isTextPath = info.handlingTextPath; info.chunk.anchor = text->style()->svgStyle()->textAnchor(); info.chunk.textLength = textContent->textLength().value(textContent); info.chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", info.chunk.isVerticalText, info.chunk.anchor);#endif } if (i > 0 && !isFirstCharacter && (*info.it).newTextChunk) { // Close mid chunk & character range ASSERT(!range.isOpen()); ASSERT(!range.isClosed()); range.endOffset = i; closeTextChunk(info);#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Close mid-text chunk, at endOffset: %i and starting new mid chunk!\n", range.endOffset);#endif // Prepare for next chunk, if we're not at the end startTextChunk(info); if (i + 1 == length) {#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Record last chunk of inline text box!\n");#endif startTextChunk(info); SVGInlineBoxCharacterRange& range = info.chunk.boxes.last(); info.assignChunkProperties = false; info.chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle()); info.chunk.isTextPath = info.handlingTextPath; info.chunk.anchor = text->style()->svgStyle()->textAnchor(); info.chunk.textLength = textContent->textLength().value(textContent); info.chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust(); range.box = curr; range.startOffset = i; ASSERT(!range.isOpen()); ASSERT(!range.isClosed()); } } // This should only hold true for the first character of the first chunk if (isFirstCharacter) isFirstCharacter = false; ++info.it; }#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Finished inline text box!\n");#endif SVGInlineBoxCharacterRange& range = info.chunk.boxes.last(); if (!range.isOpen() && !range.isClosed()) {#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Last range not closed - closing with endOffset: %i\n", length);#endif // Current text chunk is not yet closed. Finish the current range, but don't start a new chunk. range.endOffset = length; if (info.it != svgChars.end()) {#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Not at last character yet!\n");#endif // If we're not at the end of the last box to be processed, and if the next // character starts a new chunk, then close the current chunk and start a new one. if ((*info.it).newTextChunk) {#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Next character starts new chunk! Closing current chunk, and starting a new one...\n");#endif closeTextChunk(info); startTextChunk(info); } else { // Just start a new character range info.chunk.boxes.append(SVGInlineBoxCharacterRange());#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Next character does NOT start a new chunk! Starting new character range...\n");#endif } } else {#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Closing final chunk! Finished processing!\n");#endif // Close final chunk, once we're at the end of the last box closeTextChunk(info); } } } else { ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); if (!flowBox->renderer()->node()) continue; // Skip generated content. bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag);#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Handle inline flow box (%p), isTextPath=%i\n", flowBox, (int) isTextPath);#endif if (isTextPath) info.handlingTextPath = true; buildTextChunks(svgChars, flowBox, info); if (isTextPath) info.handlingTextPath = false; } }#if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " <- buildTextChunks(start=%p)\n", start);#endif}const Vector<SVGTextChunk>& SVGRootInlineBox::svgTextChunks() const { return m_svgTextChunks;}void SVGRootInlineBox::layoutTextChunks(){ Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin(); Vector<SVGTextChunk>::iterator end = m_svgTextChunks.end(); for (; it != end; ++it) { SVGTextChunk& chunk = *it;#if DEBUG_CHUNK_BUILDING > 0 { fprintf(stderr, "Handle TEXT CHUNK! anchor=%i, textLength=%f, lengthAdjust=%i, isVerticalText=%i, isTextPath=%i start=%p, end=%p -> dist: %i\n", (int) chunk.anchor, chunk.textLength, (int) chunk.lengthAdjust, (int) chunk.isVerticalText, (int) chunk.isTextPath, chunk.start, chunk.end, (unsigned int) (chunk.end - chunk.start)); Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin(); Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end(); unsigned int i = 0; for (; boxIt != boxEnd; ++boxIt) { SVGInlineBoxCharacterRange& range = *boxIt; i++; fprintf(stderr, " -> RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box); } }#endif if (chunk.isTextPath) continue; // text-path & textLength, with lengthAdjust="spacing" is already handled for textPath layouts. applyTextLengthCorrectionToTextChunk(chunk); // text-anchor is already handled for textPath layouts. applyTextAnchorToTextChunk(chunk); }}static inline void addPaintServerToTextDecorationInfo(ETextDecoration decoration, SVGTextDecorationInfo& info, RenderObject* object){ if (object->style()->svgStyle()->hasFill()) info.fillServerMap.set(decoration, object); if (object->style()->svgStyle()->hasStroke()) info.strokeServerMap.set(decoration, object);}SVGTextDecorationInfo SVGRootInlineBox::retrievePaintServersForTextDecoration(RenderObject* start){ ASSERT(start); Vector<RenderObject*> parentChain; while ((start = start->parent())) { parentChain.prepend(start); // Stop at our direct <text> parent. if (start->isSVGText()) break; } Vector<RenderObject*>::iterator it = parentChain.begin(); Vector<RenderObject*>::iterator end = parentChain.end(); SVGTextDecorationInfo info; for (; it != end; ++it) { RenderObject* object = *it; ASSERT(object); RenderStyle* style = object->style(); ASSERT(style); int decorations = style->textDecoration(); if (decorations != NONE) { if (decorations & OVERLINE) addPaintServerToTextDecorationInfo(OVERLINE, info, object); if (decorations & UNDERLINE) addPaintServerToTextDecorationInfo(UNDERLINE, info, object); if (decorations & LINE_THROUGH) addPaintServerToTextDecorationInfo(LINE_THROUGH, info, object); } } return info;}void SVGRootInlineBox::walkTextChunks(SVGTextChunkWalkerBase* walker, const SVGInlineTextBox* textBox){ ASSERT(walker); Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin(); Vector<SVGTextChunk>::iterator itEnd = m_svgTextChunks.end(); for (; it != itEnd; ++it) { SVGTextChunk& curChunk = *it; Vector<SVGInlineBoxCharacterRange>::iterator boxIt = curChunk.boxes.begin(); Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = curChunk.boxes.end(); InlineBox* lastNotifiedBox = 0; InlineBox* prevBox = 0; unsigned int chunkOffset = 0; bool startedFirstChunk = false; for (; boxIt != boxEnd; ++boxIt) { SVGInlineBoxCharacterRange& range = *boxIt; ASSERT(range.box->isInlineTextBox()); SVGInlineTextBox* rangeTextBox = static_cast<SVGInlineTextBox*>(range.box); if (textBox && rangeTextBox != textBox) { chunkOffset += range.endOffset - range.startOffset; continue; } // Eventually notify that we started a new chunk if (!textBox && !startedFirstChunk) { startedFirstChunk = true; lastNotifiedBox = range.box; walker->start(range.box); } else { // Eventually apply new style, as this chunk spans multiple boxes (with possible different styling) if (prevBox && prevBox != range.box) { lastNotifiedBox = range.box; walker->end(prevBox); walker->start(lastNotifiedBox); } } unsigned int length = range.endOffset - range.startOffset; Vector<SVGChar>::iterator itCharBegin = curChunk.start + chunkOffset; Vector<SVGChar>::iterator itCharEnd = curChunk.start + chunkOffset + length; ASSERT(itCharEnd <= curChunk.end); // Process this chunk portion if (textBox) (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); else { if (walker->setupFill(range.box)) (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); if (walker->setupStroke(range.box)) (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); } chunkOffset += length; if (!textBox) prevBox = range.box; } if (!textBox && startedFirstChunk) walker->end(lastNotifiedBox); }}} // namespace WebCore#endif // ENABLE(SVG)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -