VisiblePosition RenderSVGInlineText::positionForCoordinates(int x, int y) { SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(firstTextBox()); if (!textBox || textLength() == 0) return VisiblePosition(element(), 0, DOWNSTREAM); SVGRootInlineBox* rootBox = textBox->svgRootInlineBox(); RenderObject* object = rootBox ? rootBox->object() : 0; if (!object) return VisiblePosition(element(), 0, DOWNSTREAM); int offset = 0; for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) { if (box->svgCharacterHitsPosition(x + object->xPos(), y + object->yPos(), offset)) { // If we're not at the end/start of the box, stop looking for other selected boxes. if (box->direction() == LTR) { if (offset <= (int) box->end() + 1) break; } else { if (offset > (int) box->start()) break; } } } return VisiblePosition(element(), offset, DOWNSTREAM); }
static inline SVGInlineTextBoxQueryWalker executeTextQuery(const SVGTextContentElement* element, SVGInlineTextBoxQueryWalker::QueryMode mode, long startPosition = 0, long length = 0, FloatPoint referencePoint = FloatPoint()) { SVGRootInlineBox* rootBox = rootInlineBoxForTextContentElement(element); if (!rootBox) return SVGInlineTextBoxQueryWalker(0, mode); // Find all inline text box associated with our renderer Vector<SVGInlineTextBox*> textBoxes = findInlineTextBoxInTextChunks(element, rootBox->svgTextChunks()); // Walk text chunks to find chunks associated with our inline text box SVGInlineTextBoxQueryWalker walkerCallback(element, mode); walkerCallback.setQueryInputParameters(startPosition, length, referencePoint); SVGTextChunkWalker<SVGInlineTextBoxQueryWalker> walker(&walkerCallback, &SVGInlineTextBoxQueryWalker::chunkPortionCallback); Vector<SVGInlineTextBox*>::iterator it = textBoxes.begin(); Vector<SVGInlineTextBox*>::iterator end = textBoxes.end(); for (; it != end; ++it) { rootBox->walkTextChunks(&walker, *it); if (walkerCallback.stopProcessing()) break; } return walkerCallback; }
static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text) { SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox()); if (!box) return; Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks()); ts << " at (" << text.x() << "," << text.y() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)"; if (text.parent() && (text.parent()->style()->color() != text.style()->color())) writeNameValuePair(ts, "color", text.style()->color().name()); }
static void writeRenderSVGTextBox(TextStream& ts, const RenderSVGText& text) { SVGRootInlineBox* box = toSVGRootInlineBox(text.firstRootBox()); if (!box) return; ts << " " << enclosingIntRect(FloatRect(text.location(), FloatSize(box->logicalWidth(), box->logicalHeight()))); // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. ts << " contains 1 chunk(s)"; if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor))) writeNameValuePair(ts, "color", text.resolveColor(CSSPropertyColor).nameForRenderTreeAsText()); }
static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text) { SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox()); if (!box) return; ts << " at (" << text.x() << "," << text.y() << ") size " << box->logicalWidth() << "x" << box->logicalHeight(); // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. ts << " contains 1 chunk(s)"; if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor))) writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).name()); }
static TextStream& operator<<(TextStream& ts, const RenderSVGText& text) { SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox()); if (!box) return ts; Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks()); ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)"; if (text.parent() && (text.parent()->style()->color() != text.style()->color())) ts << " [color=" << text.style()->color().name() << "]"; return ts; }
static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text) { SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox()); if (!box) return; // FIXME: For now use an int for logicalWidth, although this makes it harder // to detect any changes caused by the conversion to floating point. :( int logicalWidth = ceilf(box->x() + box->logicalWidth()) - box->x(); ts << " at (" << text.x() << "," << text.y() << ") size " << logicalWidth << "x" << box->logicalHeight(); // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. ts << " contains 1 chunk(s)"; if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor))) writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).nameForRenderTreeAsText()); }
void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads) { InlineRunBox* firstBox = firstLineBox(); SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; RenderBox* object = rootBox ? rootBox->block() : 0; if (!object) return; int xRef = object->x(); int yRef = object->y(); for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height()); quads.append(localToAbsoluteQuad(rect)); } }
void RenderSVGTSpan::absoluteRects(Vector<IntRect>& rects, int, int, bool) { InlineRunBox* firstBox = firstLineBox(); SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; RenderObject* object = rootBox ? rootBox->object() : 0; if (!object) return; int xRef = object->xPos() + xPos(); int yRef = object->yPos() + yPos(); for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); rects.append(enclosingIntRect(absoluteTransform().mapRect(rect))); } }
void RenderSVGTextPath::absoluteQuads(Vector<FloatQuad>& quads, bool) { InlineRunBox* firstBox = firstLineBox(); SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; RenderObject* object = rootBox ? rootBox->object() : 0; if (!object) return; int xRef = object->xPos() + xPos(); int yRef = object->yPos() + yPos(); for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); // FIXME: broken with CSS transforms quads.append(absoluteTransform().mapRect(rect)); } }
void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int) { InlineRunBox* firstBox = firstLineBox(); SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; RenderBlock* object = rootBox ? rootBox->block() : 0; if (!object) return; int xRef = object->x() + x(); int yRef = object->y() + y(); for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); // FIXME: broken with CSS transforms rects.append(enclosingIntRect(absoluteTransform().mapRect(rect))); } }
VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) { SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(firstTextBox()); if (!textBox || textLength() == 0) return createVisiblePosition(0, DOWNSTREAM); SVGRootInlineBox* rootBox = textBox->svgRootInlineBox(); RenderBlock* object = rootBox ? rootBox->block() : 0; if (!object) return createVisiblePosition(0, DOWNSTREAM); int closestOffsetInBox = 0; // FIXME: This approach is wrong. The correct code would first find the // closest SVGInlineTextBox to the point, and *then* ask only that inline box // what the closest text offset to that point is. This code instead walks // through all boxes in order, so when you click "near" a box, you'll actually // end up returning the nearest offset in the last box, even if the // nearest offset to your click is contained in another box. for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) { if (box->svgCharacterHitsPosition(point.x() + object->x(), point.y() + object->y(), closestOffsetInBox)) { // If we're not at the end/start of the box, stop looking for other selected boxes. if (box->direction() == LTR) { if (closestOffsetInBox <= (int) box->end() + 1) break; } else { if (closestOffsetInBox > (int) box->start()) break; } } } return createVisiblePosition(closestOffsetInBox, DOWNSTREAM); }
static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textBox, int indent) { SVGRootInlineBox* rootBox = textBox->svgRootInlineBox(); if (!rootBox) return; Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(rootBox->svgTextChunks()); Vector<SVGTextChunk>::iterator it = chunks.begin(); Vector<SVGTextChunk>::iterator end = chunks.end(); // Write text chunks unsigned int i = 1; for (; it != end; ++it) { SVGTextChunk& cur = *it; // Write inline box character ranges Vector<SVGInlineBoxCharacterRange>::iterator boxIt = cur.boxes.begin(); Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = cur.boxes.end(); if (!containsInlineTextBox(cur, textBox)) { i++; continue; } writeIndent(ts, indent + 1); unsigned int j = 1; ts << "chunk " << i << " "; if (cur.anchor == TA_MIDDLE) { ts << "(middle anchor"; if (cur.isVerticalText) ts << ", vertical"; ts << ") "; } else if (cur.anchor == TA_END) { ts << "(end anchor"; if (cur.isVerticalText) ts << ", vertical"; ts << ") "; } else if (cur.isVerticalText) ts << "(vertical) "; unsigned int totalOffset = 0; for (; boxIt != boxEnd; ++boxIt) { SVGInlineBoxCharacterRange& range = *boxIt; unsigned int offset = range.endOffset - range.startOffset; ASSERT(cur.start + totalOffset <= cur.end); totalOffset += offset; if (textBox != static_cast<SVGInlineTextBox*>(range.box)) { j++; continue; } FloatPoint topLeft = topLeftPositionOfCharacterRange(cur.start + totalOffset - offset, cur.start + totalOffset); ts << "text run " << j << " at (" << topLeft.x() << "," << topLeft.y() << ") "; ts << "startOffset " << range.startOffset << " endOffset " << range.endOffset; if (cur.isVerticalText) ts << " height " << cummulatedHeightOfInlineBoxCharacterRange(range); else ts << " width " << cummulatedWidthOfInlineBoxCharacterRange(range); if (textBox->direction() == RTL || textBox->m_dirOverride) { ts << (textBox->direction() == RTL ? " RTL" : " LTR"); if (textBox->m_dirOverride) ts << " override"; } ts << ": " << quoteAndEscapeNonPrintables(String(textBox->textRenderer()->text()).substring(textBox->start() + range.startOffset, offset)) << "\n"; j++; } i++; } }