void SVGTextChunkLayoutInfo::recursiveBuildTextChunks(InlineFlowBox* start) { #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(); ASSERT(length > 0); #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) m_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 = m_svgTextChunks.isEmpty() && m_chunk.start == m_charsIt && m_chunk.start == m_chunk.end; if (isFirstCharacter) { ASSERT(m_chunk.boxes.isEmpty()); m_chunk.boxes.append(SVGInlineBoxCharacterRange()); } else ASSERT(!m_chunk.boxes.isEmpty()); // Walk string to find out new chunk positions, if existent for (unsigned i = 0; i < length; ++i) { ASSERT(m_charsIt != m_charsEnd); SVGInlineBoxCharacterRange& range = m_chunk.boxes.last(); if (range.isOpen()) { range.box = curr; range.startOffset = !i ? 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 (m_assignChunkProperties) { m_assignChunkProperties = false; m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle()); m_chunk.isTextPath = m_handlingTextPath; m_chunk.anchor = text->style()->svgStyle()->textAnchor(); m_chunk.textLength = textContent->textLength().value(textContent); m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust(); #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", m_chunk.isVerticalText, m_chunk.anchor); #endif } if (i > 0 && !isFirstCharacter && m_charsIt->newTextChunk) { // Close mid chunk & character range ASSERT(!range.isOpen()); ASSERT(!range.isClosed()); range.endOffset = i; closeTextChunk(); #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(); if (i + 1 == length) { #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Record last chunk of inline text box!\n"); #endif startTextChunk(); SVGInlineBoxCharacterRange& range = m_chunk.boxes.last(); m_assignChunkProperties = false; m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle()); m_chunk.isTextPath = m_handlingTextPath; m_chunk.anchor = text->style()->svgStyle()->textAnchor(); m_chunk.textLength = textContent->textLength().value(textContent); m_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; ++m_charsIt; } #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Finished inline text box!\n"); #endif SVGInlineBoxCharacterRange& range = m_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 (m_charsIt != m_charsEnd) { #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 (m_charsIt->newTextChunk) { #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Next character starts new chunk! Closing current chunk, and starting a new one...\n"); #endif closeTextChunk(); startTextChunk(); } else { // Just start a new character range m_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(); } } } else { ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); // Skip generated content. if (!flowBox->renderer()->node()) continue; 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) m_handlingTextPath = true; recursiveBuildTextChunks(flowBox); if (isTextPath) m_handlingTextPath = false; } } #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " <- buildTextChunks(start=%p)\n", start); #endif }
void RenderListItem::positionListMarker() { if (m_marker && m_marker->parent()->isBox() && !m_marker->isInside() && m_marker->inlineBoxWrapper()) { LayoutUnit markerOldLogicalLeft = m_marker->logicalLeft(); LayoutUnit blockOffset = 0; LayoutUnit lineOffset = 0; for (RenderBox* o = m_marker->parentBox(); o != this; o = o->parentBox()) { blockOffset += o->logicalTop(); lineOffset += o->logicalLeft(); } bool adjustOverflow = false; LayoutUnit markerLogicalLeft; bool hitSelfPaintingLayer = false; const RootInlineBox& rootBox = m_marker->inlineBoxWrapper()->root(); LayoutUnit lineTop = rootBox.lineTop(); LayoutUnit lineBottom = rootBox.lineBottom(); // FIXME: Need to account for relative positioning in the layout overflow. if (style().isLeftToRightDirection()) { LayoutUnit leftLineOffset = logicalLeftOffsetForLine(blockOffset, logicalLeftOffsetForLine(blockOffset, DoNotIndentText), false); markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - borderStart() + m_marker->marginStart(); m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom); LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom); if (markerLogicalLeft < newLogicalVisualOverflowRect.x() && !hitSelfPaintingLayer) { newLogicalVisualOverflowRect.setWidth(newLogicalVisualOverflowRect.maxX() - markerLogicalLeft); newLogicalVisualOverflowRect.setX(markerLogicalLeft); if (box == &rootBox) adjustOverflow = true; } if (markerLogicalLeft < newLogicalLayoutOverflowRect.x()) { newLogicalLayoutOverflowRect.setWidth(newLogicalLayoutOverflowRect.maxX() - markerLogicalLeft); newLogicalLayoutOverflowRect.setX(markerLogicalLeft); if (box == &rootBox) adjustOverflow = true; } box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom); if (box->renderer().hasSelfPaintingLayer()) hitSelfPaintingLayer = true; } } else { LayoutUnit rightLineOffset = logicalRightOffsetForLine(blockOffset, logicalRightOffsetForLine(blockOffset, DoNotIndentText), false); markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd(); m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom); LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom); if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVisualOverflowRect.maxX() && !hitSelfPaintingLayer) { newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalVisualOverflowRect.x()); if (box == &rootBox) adjustOverflow = true; } if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) { newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalLayoutOverflowRect.x()); if (box == &rootBox) adjustOverflow = true; } box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom); if (box->renderer().hasSelfPaintingLayer()) hitSelfPaintingLayer = true; } } if (adjustOverflow) { LayoutRect markerRect(markerLogicalLeft + lineOffset, blockOffset, m_marker->width(), m_marker->height()); if (!style().isHorizontalWritingMode()) markerRect = markerRect.transposedRect(); RenderBox* o = m_marker; bool propagateVisualOverflow = true; bool propagateLayoutOverflow = true; do { o = o->parentBox(); if (o->hasOverflowClip()) propagateVisualOverflow = false; if (is<RenderBlock>(*o)) { if (propagateVisualOverflow) downcast<RenderBlock>(*o).addVisualOverflow(markerRect); if (propagateLayoutOverflow) downcast<RenderBlock>(*o).addLayoutOverflow(markerRect); } if (o->hasOverflowClip()) propagateLayoutOverflow = false; if (o->hasSelfPaintingLayer()) propagateVisualOverflow = false; markerRect.moveBy(-o->location()); } while (o != this && propagateVisualOverflow && propagateLayoutOverflow); } } }