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); }
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 dumpTextBoxes(Vector<SVGInlineTextBox*>& boxes) { unsigned boxCount = boxes.size(); fprintf(stderr, "Dumping all text fragments in text sub tree, %i boxes\n", boxCount); for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { SVGInlineTextBox* textBox = boxes.at(boxPosition); Vector<SVGTextFragment>& fragments = textBox->textFragments(); fprintf(stderr, "-> Box %i: Dumping text fragments for SVGInlineTextBox, textBox=%p, textRenderer=%p\n", boxPosition, textBox, textBox->textRenderer()); fprintf(stderr, " textBox properties, start=%i, len=%i, box direction=%i\n", textBox->start(), textBox->len(), textBox->direction()); fprintf(stderr, " textRenderer properties, textLength=%i\n", textBox->textRenderer()->textLength()); const UChar* characters = textBox->textRenderer()->characters(); unsigned fragmentCount = fragments.size(); for (unsigned i = 0; i < fragmentCount; ++i) { SVGTextFragment& fragment = fragments.at(i); String fragmentString(characters + fragment.characterOffset, fragment.length); fprintf(stderr, " -> Fragment %i, x=%lf, y=%lf, width=%lf, height=%lf, characterOffset=%i, length=%i, characters='%s'\n" , i, fragment.x, fragment.y, fragment.width, fragment.height, fragment.characterOffset, fragment.length, fragmentString.utf8().data()); } } }