示例#1
0
void RenderTextLineBoxes::remove(InlineTextBox& box)
{
    checkConsistency();

    if (&box == m_first)
        m_first = box.nextTextBox();
    if (&box == m_last)
        m_last = box.prevTextBox();
    if (box.nextTextBox())
        box.nextTextBox()->setPreviousTextBox(box.prevTextBox());
    if (box.prevTextBox())
        box.prevTextBox()->setNextTextBox(box.nextTextBox());

    checkConsistency();
}
FloatRect LayoutSVGInlineText::floatLinesBoundingBox() const
{
    FloatRect boundingBox;
    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
        boundingBox.unite(box->calculateBoundaries().toFloatRect());
    return boundingBox;
}
IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPos)
{
    IntRect rect;

    RenderBlock* cb = containingBlock();
    if (!cb || !cb->container())
        return rect;

    RenderSVGRoot* root = findSVGRootObject(parent());
    if (!root)
        return rect;

    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
        rect.unite(box->selectionRect(0, 0, startPos, endPos));

    // Mimic RenderBox::computeAbsoluteRepaintRect() functionality. But only the subset needed for SVG and respecting SVG transformations.
    int x, y;
    cb->container()->absolutePosition(x, y);

    // Remove HTML parent translation offsets here! These need to be retrieved from the RenderSVGRoot object.
    // But do take the containingBlocks's container position into account, ie. SVG text in scrollable <div>.
    AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform();

    FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + x - xPos() - htmlParentCtm.e()), narrowPrecisionToFloat(rect.y() + y - yPos() - htmlParentCtm.f()), rect.width(), rect.height());
    return enclosingIntRect(absoluteTransform().mapRect(fixedRect));
}
void write(TextStream& ts, const RenderObject& o, int indent)
{
#if ENABLE(SVG)
    if (o.isRenderPath()) {
        write(ts, *toRenderPath(&o), indent);
        return;
    }
    if (o.isSVGContainer()) {
        writeSVGContainer(ts, o, indent);
        return;
    }
    if (o.isSVGRoot()) {
        write(ts, *toRenderSVGRoot(&o), indent);
        return;
    }
    if (o.isSVGText()) {
        if (!o.isText())
            writeSVGText(ts, *toRenderBlock(&o), indent);
        else
            writeSVGInlineText(ts, *toRenderText(&o), indent);
        return;
    }
    if (o.isSVGImage()) {
        writeSVGImage(ts, *toRenderImage(&o), indent);
        return;
    }
#endif

    writeIndent(ts, indent);

    ts << o << "\n";

    if (o.isText() && !o.isBR()) {
        const RenderText& text = *toRenderText(&o);
        for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
            writeIndent(ts, indent + 1);
            writeTextRun(ts, text, *box);
        }
    }

    for (RenderObject* child = o.firstChild(); child; child = child->nextSibling()) {
        if (child->hasLayer())
            continue;
        write(ts, *child, indent + 1);
    }

    if (o.isWidget()) {
        Widget* widget = toRenderWidget(&o)->widget();
        if (widget && widget->isFrameView()) {
            FrameView* view = static_cast<FrameView*>(widget);
            RenderView* root = view->frame()->contentRenderer();
            if (root) {
                view->layout();
                RenderLayer* l = root->layer();
                if (l)
                    writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), indent + 1);
            }
        }
    }
}
示例#5
0
IntRect RenderSVGInlineText::linesBoundingBox() const
{
    IntRect boundingBox;
    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
        boundingBox.unite(box->calculateBoundaries());
    return boundingBox;
}
static void write(QTextStream &ts, const RenderObject &o, int indent = 0)
{
    writeIndent(ts, indent);
    
    ts << o << "\n";
    
    if (o.isText() && !o.isBR()) {
        const RenderText &text = static_cast<const RenderText &>(o);
        for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
            writeIndent(ts, indent+1);
            writeTextRun(ts, text, *box);
        }
    }

    for (RenderObject *child = o.firstChild(); child; child = child->nextSibling()) {
        if (child->layer()) {
            continue;
        }
        write(ts, *child, indent + 1);
    }
    
    if (o.isWidget()) {
        QWidget *widget = static_cast<const RenderWidget &>(o).widget();
        if (widget && widget->inherits("KHTMLView")) {
            KHTMLView *view = static_cast<KHTMLView *>(widget);
            RenderObject *root = KWQ(view->part())->renderer();
            if (root) {
                view->layout();
                RenderLayer* l = root->layer();
                if (l)
                    writeLayers(ts, l, l, QRect(l->xPos(), l->yPos(), l->width(), l->height()), indent+1);
            }
        }
    }
}
static PangoLayout* getPangoLayoutForAtk(AtkText* textObject)
{
    AccessibilityObject* coreObject = core(textObject);

    HostWindow* hostWindow = coreObject->document()->view()->hostWindow();
    if (!hostWindow)
        return 0;
    PlatformPageClient webView = hostWindow->platformPageClient();
    if (!webView)
        return 0;

    GString* str = g_string_new(NULL);

    AccessibilityRenderObject* accObject = static_cast<AccessibilityRenderObject*>(coreObject);
    if (!accObject)
        return 0;
    RenderText* renderText = toRenderText(accObject->renderer());
    if (!renderText)
        return 0;

    // Create a string with the layout as it appears on the screen
    InlineTextBox* box = renderText->firstTextBox();
    while (box) {
        gchar *text = convertUniCharToUTF8(renderText->characters(), renderText->textLength(), box->start(), box->end());
        g_string_append(str, text);
        g_string_append(str, "\n");
        box = box->nextTextBox();
    }

    PangoLayout* layout = gtk_widget_create_pango_layout(static_cast<GtkWidget*>(webView), g_string_free(str, FALSE));
    g_object_set_data_full(G_OBJECT(textObject), "webkit-accessible-pango-layout", layout, g_object_unref);
    return layout;
}
示例#8
0
static void collectTextBoxesInLogicalOrder(LineLayoutSVGInlineText textLineLayout, Vector<SVGInlineTextBox*>& textBoxes)
{
    textBoxes.shrink(0);
    for (InlineTextBox* textBox = textLineLayout.firstTextBox(); textBox; textBox = textBox->nextTextBox())
        textBoxes.append(toSVGInlineTextBox(textBox));
    std::sort(textBoxes.begin(), textBoxes.end(), InlineTextBox::compareByStart);
}
Position Position::upstream(EStayInBlock stayInBlock) const
{
    Position start = equivalentDeepPosition();
    NodeImpl *startNode = start.node();
    if (!startNode)
        return Position();

    NodeImpl *block = startNode->enclosingBlockFlowOrTableElement();
    Position lastVisible;
    
    PositionIterator it(start);
    for (; !it.atStart(); it.previous()) {
        NodeImpl *currentNode = it.current().node();

        if (stayInBlock) {
            NodeImpl *currentBlock = currentNode->enclosingBlockFlowOrTableElement();
            if (block != currentBlock)
                return it.next();
        }

        RenderObject *renderer = currentNode->renderer();
        if (!renderer)
            continue;

        if (renderer->style()->visibility() != VISIBLE)
            continue;

        lastVisible = it.current();

        if (renderer->isReplaced() || renderer->isBR()) {
            if (it.current().offset() >= renderer->caretMaxOffset())
                return Position(currentNode, renderer->caretMaxOffset());
            else
                continue;
        }

        if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
            if (currentNode != startNode)
                return Position(currentNode, renderer->caretMaxOffset());

            if (it.current().offset() < 0)
                continue;
            uint textOffset = it.current().offset();

            RenderText *textRenderer = static_cast<RenderText *>(renderer);
            for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                if (textOffset > box->start() && textOffset <= box->start() + box->len())
                    return it.current();
                else if (box != textRenderer->lastTextBox() && 
                         !box->nextOnLine() && 
                         textOffset == box->start() + box->len() + 1)
                    return it.current();
            }
        }
    }
    
    return lastVisible.isNotNull() ? lastVisible : *this;
}
void SVGInlineTextBox::paintTextMatchMarker(GraphicsContext* context, const FloatPoint&, DocumentMarker* marker, RenderStyle* style, const Font& font)
{
    // SVG is only interested in the TextMatch markers.
    if (marker->type() != DocumentMarker::TextMatch)
        return;

    RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer());
    ASSERT(textRenderer);

    FloatRect markerRect;
    AffineTransform fragmentTransform;
    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
        if (!box->isSVGInlineTextBox())
            continue;

        SVGInlineTextBox* textBox = toSVGInlineTextBox(box);

        int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0);
        int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len());

        if (markerStartPosition >= markerEndPosition)
            continue;

        const Vector<SVGTextFragment>& fragments = textBox->textFragments();
        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);

            int fragmentStartPosition = markerStartPosition;
            int fragmentEndPosition = markerEndPosition;
            if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
                continue;

            FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
            fragment.buildFragmentTransform(fragmentTransform);
            bool fragmentTransformIsIdentity = fragmentTransform.isIdentity();

            // Draw the marker highlight.
            if (renderer()->frame()->editor().markedTextMatchesAreHighlighted()) {
                Color color = marker->activeMatch() ?
                    RenderTheme::theme().platformActiveTextSearchHighlightColor() :
                    RenderTheme::theme().platformInactiveTextSearchHighlightColor();
                GraphicsContextStateSaver stateSaver(*context);
                if (!fragmentTransformIsIdentity)
                    context->concatCTM(fragmentTransform);
                context->setFillColor(color);
                context->fillRect(fragmentRect, color);
            }

            if (!fragmentTransformIsIdentity)
                fragmentRect = fragmentTransform.mapRect(fragmentRect);
            markerRect.unite(fragmentRect);
        }
    }

    toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox());
}
示例#11
0
void SVGInlineTextBox::dirtyLineBoxes()
{
    dirtyOwnLineBoxes();

    // And clear any following text fragments as the text on which they
    // depend may now no longer exist, or glyph positions may be wrong
    for (InlineTextBox* nextBox = nextTextBox(); nextBox; nextBox = nextBox->nextTextBox())
        nextBox->dirtyOwnLineBoxes();
}
void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText* textRenderer)
{
    ASSERT(textRenderer);

    Node* node = textRenderer->node();
    if (!node || !node->inDocument())
        return;

    RenderStyle* style = textRenderer->style();
    ASSERT(style);

    Document* document = textRenderer->document();
    Vector<DocumentMarker> markers = document->markers()->markersForNode(textRenderer->node());

    Vector<DocumentMarker>::iterator markerEnd = markers.end();
    for (Vector<DocumentMarker>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) {
        const DocumentMarker& marker = *markerIt;

        // SVG is only interessted in the TextMatch marker, for now.
        if (marker.type != DocumentMarker::TextMatch)
            continue;

        FloatRect markerRect;
        for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
            ASSERT(box->isSVGInlineTextBox());
            SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);

            int markerStartPosition = max<int>(marker.startOffset - textBox->start(), 0);
            int markerEndPosition = min<int>(marker.endOffset - textBox->start(), textBox->len());

            if (markerStartPosition >= markerEndPosition)
                continue;

            int fragmentStartPosition = 0;
            int fragmentEndPosition = 0;

            const Vector<SVGTextFragment>& fragments = textBox->textFragments();
            unsigned textFragmentsSize = fragments.size();
            for (unsigned i = 0; i < textFragmentsSize; ++i) {
                const SVGTextFragment& fragment = fragments.at(i);

                fragmentStartPosition = markerStartPosition;
                fragmentEndPosition = markerEndPosition;
                if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
                    continue;

                FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
                if (!fragment.transform.isIdentity())
                    fragmentRect = fragment.transform.mapRect(fragmentRect);

                markerRect.unite(fragmentRect);
            }
        }

        document->markers()->setRenderedRectForMarker(node, marker, textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox());
    }
}
static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent)
{
    for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
        if (!box->isSVGInlineTextBox())
            continue;

        writeSVGInlineTextBox(ts, toSVGInlineTextBox(box), indent);
    }
}
PositionWithAffinity LayoutSVGInlineText::positionForPoint(const LayoutPoint& point)
{
    if (!firstTextBox() || !textLength())
        return createPositionWithAffinity(0, DOWNSTREAM);

    ASSERT(m_scalingFactor);
    float baseline = m_scaledFont.fontMetrics().floatAscent() / m_scalingFactor;

    LayoutBlock* containingBlock = this->containingBlock();
    ASSERT(containingBlock);

    // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
    FloatPoint absolutePoint(point);
    absolutePoint.moveBy(containingBlock->location());

    float closestDistance = std::numeric_limits<float>::max();
    float closestDistancePosition = 0;
    const SVGTextFragment* closestDistanceFragment = 0;
    SVGInlineTextBox* closestDistanceBox = 0;

    AffineTransform fragmentTransform;
    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
        if (!box->isSVGInlineTextBox())
            continue;

        SVGInlineTextBox* textBox = toSVGInlineTextBox(box);
        Vector<SVGTextFragment>& fragments = textBox->textFragments();

        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);
            FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
            fragment.buildFragmentTransform(fragmentTransform);
            if (!fragmentTransform.isIdentity())
                fragmentRect = fragmentTransform.mapRect(fragmentRect);

            float distance = 0;
            if (!fragmentRect.contains(absolutePoint))
                distance = squaredDistanceToClosestPoint(fragmentRect, absolutePoint);

            if (distance <= closestDistance) {
                closestDistance = distance;
                closestDistanceBox = textBox;
                closestDistanceFragment = &fragment;
                closestDistancePosition = fragmentRect.x();
            }
        }
    }

    if (!closestDistanceFragment)
        return createPositionWithAffinity(0, DOWNSTREAM);

    int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true);
    return createPositionWithAffinity(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
}
示例#15
0
VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point, const RenderRegion*)
{
    if (!firstTextBox() || !textLength())
        return createVisiblePosition(0, DOWNSTREAM);

    float baseline = m_scaledFont.fontMetrics().floatAscent();

    RenderBlock* containingBlock = this->containingBlock();
    ASSERT(containingBlock);

    // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
    FloatPoint absolutePoint(point);
    absolutePoint.moveBy(containingBlock->location());

    float closestDistance = std::numeric_limits<float>::max();
    float closestDistancePosition = 0;
    const SVGTextFragment* closestDistanceFragment = nullptr;
    SVGInlineTextBox* closestDistanceBox = nullptr;

    AffineTransform fragmentTransform;
    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
        if (!is<SVGInlineTextBox>(*box))
            continue;

        auto& textBox = downcast<SVGInlineTextBox>(*box);
        Vector<SVGTextFragment>& fragments = textBox.textFragments();

        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);
            FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
            fragment.buildFragmentTransform(fragmentTransform);
            if (!fragmentTransform.isIdentity())
                fragmentRect = fragmentTransform.mapRect(fragmentRect);

            float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) +
                             powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2);

            if (distance < closestDistance) {
                closestDistance = distance;
                closestDistanceBox = &textBox;
                closestDistanceFragment = &fragment;
                closestDistancePosition = fragmentRect.x();
            }
        }
    }

    if (!closestDistanceFragment)
        return createVisiblePosition(0, DOWNSTREAM);

    int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true);
    return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
}
示例#16
0
VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point)
{
    if (!firstTextBox() || !textLength())
        return createVisiblePosition(0, DOWNSTREAM);

    RenderStyle* style = this->style();
    ASSERT(style);
    int baseline = style->font().ascent();

    RenderBlock* containingBlock = this->containingBlock();
    ASSERT(containingBlock);

    // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
    FloatPoint absolutePoint(point);
    absolutePoint.move(containingBlock->x(), containingBlock->y());

    float closestDistance = std::numeric_limits<float>::max();
    float closestDistancePosition = 0;
    const SVGTextFragment* closestDistanceFragment = 0;
    SVGInlineTextBox* closestDistanceBox = 0;

    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
        ASSERT(box->isSVGInlineTextBox());
        SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
        Vector<SVGTextFragment>& fragments = textBox->textFragments();

        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);
            FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
            if (!fragment.transform.isIdentity())
                fragmentRect = fragment.transform.mapRect(fragmentRect);

            float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) +
                             powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2);

            if (distance < closestDistance) {
                closestDistance = distance;
                closestDistanceBox = textBox;
                closestDistanceFragment = &fragment;
                closestDistancePosition = fragmentRect.x();
            }
        }
    }

    if (!closestDistanceFragment)
        return createVisiblePosition(0, DOWNSTREAM);

    int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true);
    return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
}
void SVGInlineTextBoxPainter::paintTextMatchMarker(GraphicsContext* context, const LayoutPoint&, DocumentMarker* marker, const ComputedStyle& style, const Font& font)
{
    // SVG is only interested in the TextMatch markers.
    if (marker->type() != DocumentMarker::TextMatch)
        return;

    LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(m_svgInlineTextBox.layoutObject());

    AffineTransform fragmentTransform;
    for (InlineTextBox* box = textLayoutObject.firstTextBox(); box; box = box->nextTextBox()) {
        if (!box->isSVGInlineTextBox())
            continue;

        SVGInlineTextBox* textBox = toSVGInlineTextBox(box);

        int markerStartPosition = std::max<int>(marker->startOffset() - textBox->start(), 0);
        int markerEndPosition = std::min<int>(marker->endOffset() - textBox->start(), textBox->len());

        if (markerStartPosition >= markerEndPosition)
            continue;

        const Vector<SVGTextFragment>& fragments = textBox->textFragments();
        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);

            int fragmentStartPosition = markerStartPosition;
            int fragmentEndPosition = markerEndPosition;
            if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
                continue;

            FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
            fragment.buildFragmentTransform(fragmentTransform);

            // Draw the marker highlight.
            if (m_svgInlineTextBox.layoutObject().frame()->editor().markedTextMatchesAreHighlighted()) {
                Color color = marker->activeMatch() ?
                    LayoutTheme::theme().platformActiveTextSearchHighlightColor() :
                    LayoutTheme::theme().platformInactiveTextSearchHighlightColor();
                GraphicsContextStateSaver stateSaver(*context);
                if (!fragmentTransform.isIdentity())
                    context->concatCTM(fragmentTransform);
                context->setFillColor(color);
                context->fillRect(fragmentRect, color);
            }
        }
    }
}
FloatQuad RenderSVGInlineText::computeRepaintQuadForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos)
{
    RenderBlock* cb = containingBlock();
    if (!cb || !cb->container())
        return FloatQuad();

    RenderSVGRoot* root = findSVGRootObject(parent());
    if (!root)
        return FloatQuad();

    IntRect rect;
    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
        rect.unite(box->selectionRect(0, 0, startPos, endPos));

    return localToContainerQuad(FloatQuad(rect), repaintContainer);
}
示例#19
0
PositionWithAffinity LayoutSVGInlineText::positionForPoint(const LayoutPoint& point)
{
    if (!hasTextBoxes() || !textLength())
        return createPositionWithAffinity(0);

    ASSERT(m_scalingFactor);
    float baseline = m_scaledFont.getFontMetrics().floatAscent() / m_scalingFactor;

    LayoutBlock* containingBlock = this->containingBlock();
    ASSERT(containingBlock);

    // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
    FloatPoint absolutePoint(point);
    absolutePoint.moveBy(containingBlock->location());

    float closestDistance = std::numeric_limits<float>::max();
    float closestDistancePosition = 0;
    const SVGTextFragment* closestDistanceFragment = nullptr;
    SVGInlineTextBox* closestDistanceBox = nullptr;

    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
        if (!box->isSVGInlineTextBox())
            continue;

        SVGInlineTextBox* textBox = toSVGInlineTextBox(box);
        for (const SVGTextFragment& fragment : textBox->textFragments()) {
            FloatRect fragmentRect = fragment.boundingBox(baseline);

            float distance = 0;
            if (!fragmentRect.contains(absolutePoint))
                distance = fragmentRect.squaredDistanceTo(absolutePoint);

            if (distance <= closestDistance) {
                closestDistance = distance;
                closestDistanceBox = textBox;
                closestDistanceFragment = &fragment;
                closestDistancePosition = fragmentRect.x();
            }
        }
    }

    if (!closestDistanceFragment)
        return createPositionWithAffinity(0);

    int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, LayoutUnit(absolutePoint.x() - closestDistancePosition), true);
    return createPositionWithAffinity(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : TextAffinity::Downstream);
}
bool VisiblePosition::isCandidate(const Position &pos)
{
    if (pos.isNull())
        return false;

    RenderObject *renderer = pos.node()->renderer();
    if (!renderer)
        return false;

    if (renderer->style()->visibility() != VISIBLE)
        return false;

    if (renderer->isReplaced())
        // return true for replaced elements
        return pos.offset() == 0 || pos.offset() == 1;

    if (renderer->isBR()) {
        if (pos.offset() == 0) {
            InlineBox* box = static_cast<RenderText*>(renderer)->firstTextBox();
            if (box) {
                // return true for offset 0 into BR element on a line by itself
                RootInlineBox* root = box->root();
                if (root)
                    return root->firstLeafChild() == box && root->lastLeafChild() == box;
            }
        }
        return false;
    }

    if (renderer->isText()) {
        RenderText *textRenderer = static_cast<RenderText *>(renderer);
        for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
            if (pos.offset() >= box->m_start && pos.offset() <= box->m_start + box->m_len) {
                // return true if in a text node
                return true;
            }
        }
    }

    if (renderer->isBlockFlow() && (!renderer->firstChild() || !pos.node()->firstChild()) &&
            (renderer->height() || pos.node()->id() == ID_BODY)) {
        // return true for offset 0 into rendered blocks that are empty of rendered kids, but have a height
        return pos.offset() == 0;
    }

    return false;
}
示例#21
0
bool TextIterator::handleTextNode()
{
    RenderText* renderer = static_cast<RenderText*>(m_node->renderer());
    if (renderer->style()->visibility() != VISIBLE)
        return false;
        
    m_lastTextNode = m_node;
    String str = renderer->text();

    // handle pre-formatted text
    if (!renderer->style()->collapseWhiteSpace()) {
        int runStart = m_offset;
        if (m_lastTextNodeEndedWithCollapsedSpace) {
            emitCharacter(' ', m_node, 0, runStart, runStart);
            return false;
        }
        int strLength = str.length();
        int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX;
        int runEnd = min(strLength, end);

        if (runStart >= runEnd)
            return true;

        emitText(m_node, runStart, runEnd);
        return true;
    }

    if (!renderer->firstTextBox() && str.length() > 0) {
        m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space
        return true;
    }

    // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
    if (renderer->containsReversedText()) {
        m_sortedTextBoxes.clear();
        for (InlineTextBox * textBox = renderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
            m_sortedTextBoxes.append(textBox);
        }
        std::sort(m_sortedTextBoxes.begin(), m_sortedTextBoxes.end(), compareBoxStart); 
        m_sortedTextBoxesPosition = 0;
    }
    
    m_textBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox();
    handleTextBox();
    return true;
}
bool Position::inRenderedContent() const
{
    if (isNull())
        return false;
        
    RenderObject *renderer = node()->renderer();
    if (!renderer)
        return false;
    
    if (renderer->style()->visibility() != VISIBLE)
        return false;

    // FIXME: This check returns false for a <br> at the end of a line!
    if (renderer->isBR() && static_cast<RenderText *>(renderer)->firstTextBox()) {
        return offset() == 0;
    }
    else if (renderer->isText()) {
        RenderText *textRenderer = static_cast<RenderText *>(renderer);
        for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
            if (offset() >= box->m_start && offset() <= box->m_start + box->m_len) {
                return true;
            }
            else if (offset() < box->m_start) {
                // The offset we're looking for is before this node
                // this means the offset must be in content that is
                // not rendered. Return false.
                return false;
            }
        }
    }
    else if (offset() >= renderer->caretMinOffset() && offset() <= renderer->caretMaxOffset()) {
        // return true for replaced elements, for inline flows if they have a line box
        // and for blocks if they are empty
        if (renderer->isReplaced() ||
            (renderer->isInlineFlow() && static_cast<RenderFlow *>(renderer)->firstLineBox()) ||
            (renderer->isBlockFlow() && !renderer->firstChild() && renderer->height()))
            return true;
    }
    
    return false;
}
示例#23
0
void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavior behavior)
{
    writeIndent(ts, indent);

    RenderTreeAsText::writeRenderObject(ts, o, behavior);
    ts << "\n";

    if (o.isText()) {
        const RenderText& text = toRenderText(o);
        for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
            writeIndent(ts, indent + 1);
            writeTextRun(ts, text, *box);
        }
    }

    for (RenderObject* child = o.slowFirstChild(); child; child = child->nextSibling()) {
        if (child->hasLayer())
            continue;
        write(ts, *child, indent + 1, behavior);
    }
}
long Position::renderedOffset() const
{
    if (!node()->isTextNode())
        return offset();
   
    if (!node()->renderer())
        return offset();
                    
    long result = 0;
    RenderText *textRenderer = static_cast<RenderText *>(node()->renderer());
    for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
        long start = box->m_start;
        long end = box->m_start + box->m_len;
        if (offset() < start)
            return result;
        if (offset() <= end) {
            result += offset() - start;
            return result;
        }
        result += box->m_len;
    }
    return result;
}
bool Position::isRenderedCharacter() const
{
    if (isNull() || !node()->isTextNode())
        return false;
        
    RenderObject *renderer = node()->renderer();
    if (!renderer)
        return false;
    
    RenderText *textRenderer = static_cast<RenderText *>(renderer);
    for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
        if (offset() < box->m_start) {
            // The offset we're looking for is before this node
            // this means the offset must be in content that is
            // not rendered. Return false.
            return false;
        }
        if (offset() >= box->m_start && offset() < box->m_start + box->m_len)
            return true;
    }
    
    return false;
}
示例#26
0
// Bounds of the LayoutObject relative to the scroller's visible content rect.
static LayoutRect relativeBounds(const LayoutObject* layoutObject,
                                 const ScrollableArea* scroller) {
  LayoutRect localBounds;
  if (layoutObject->isBox()) {
    localBounds = toLayoutBox(layoutObject)->borderBoxRect();
    if (!layoutObject->hasOverflowClip()) {
      // borderBoxRect doesn't include overflow content and floats.
      LayoutUnit maxHeight =
          std::max(localBounds.height(),
                   toLayoutBox(layoutObject)->layoutOverflowRect().height());
      if (layoutObject->isLayoutBlockFlow() &&
          toLayoutBlockFlow(layoutObject)->containsFloats()) {
        // Note that lowestFloatLogicalBottom doesn't include floating
        // grandchildren.
        maxHeight = std::max(
            maxHeight,
            toLayoutBlockFlow(layoutObject)->lowestFloatLogicalBottom());
      }
      localBounds.setHeight(maxHeight);
    }
  } else if (layoutObject->isText()) {
    // TODO(skobes): Use first and last InlineTextBox only?
    for (InlineTextBox* box = toLayoutText(layoutObject)->firstTextBox(); box;
         box = box->nextTextBox())
      localBounds.unite(box->frameRect());
  } else {
    // Only LayoutBox and LayoutText are supported.
    ASSERT_NOT_REACHED();
  }

  LayoutRect relativeBounds = LayoutRect(
      scroller->localToVisibleContentQuad(FloatRect(localBounds), layoutObject)
          .boundingBox());

  return relativeBounds;
}
示例#27
0
bool Position::inRenderedText() const
{
    if (isNull() || !node()->isTextNode())
        return false;
        
    RenderObject *renderer = node()->renderer();
    if (!renderer)
        return false;
    
    RenderText *textRenderer = static_cast<RenderText *>(renderer);
    for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
        if (offset() < box->m_start && !textRenderer->containsReversedText()) {
            // The offset we're looking for is before this node
            // this means the offset must be in content that is
            // not rendered. Return false.
            return false;
        }
        if (box->containsCaretOffset(offset()))
            // Return false for offsets inside composed characters.
            return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset()));
    }
    
    return false;
}
static gchar* textForRenderer(RenderObject* renderer)
{
    GString* resultText = g_string_new(0);

    if (!renderer)
        return g_string_free(resultText, FALSE);

    // For RenderBlocks, piece together the text from the RenderText objects they contain.
    for (RenderObject* object = renderer->firstChild(); object; object = object->nextSibling()) {
        if (object->isBR()) {
            g_string_append(resultText, "\n");
            continue;
        }

        RenderText* renderText;
        if (object->isText())
            renderText = toRenderText(object);
        else {
            // List item's markers will be treated in an special way
            // later on this function, so ignore them here.
            if (object->isReplaced() && !renderer->isListItem())
                g_string_append_unichar(resultText, objectReplacementCharacter);

            // We need to check children, if any, to consider when
            // current object is not a text object but some of its
            // children are, in order not to miss those portions of
            // text by not properly handling those situations
            if (object->firstChild())
                g_string_append(resultText, textForRenderer(object));

            continue;
        }

        InlineTextBox* box = renderText ? renderText->firstTextBox() : 0;
        while (box) {
            // WebCore introduces line breaks in the text that do not reflect
            // the layout you see on the screen, replace them with spaces.
            String text = String(renderText->characters(), renderText->textLength()).replace("\n", " ");
            g_string_append(resultText, text.substring(box->start(), box->end() - box->start() + 1).utf8().data());

            // Newline chars in the source result in separate text boxes, so check
            // before adding a newline in the layout. See bug 25415 comment #78.
            // If the next sibling is a BR, we'll add the newline when we examine that child.
            if (!box->nextOnLineExists() && !(object->nextSibling() && object->nextSibling()->isBR())) {
                // If there was a '\n' in the last position of the
                // current text box, it would have been converted to a
                // space in String::replace(), so remove it first.
                if (renderText->characters()[box->end()] == '\n')
                    g_string_erase(resultText, resultText->len - 1, -1);

                g_string_append(resultText, "\n");
            }
            box = box->nextTextBox();
        }
    }

    // Insert the text of the marker for list item in the right place, if present
    if (renderer->isListItem()) {
        String markerText = toRenderListItem(renderer)->markerTextWithSuffix();
        if (renderer->style()->direction() == LTR)
            g_string_prepend(resultText, markerText.utf8().data());
        else
            g_string_append(resultText, markerText.utf8().data());
    }

    return g_string_free(resultText, FALSE);
}
static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent)
{
    for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox())
        writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent);
}
void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, const RenderRegion* region) const
{
    LayoutUnit logicalTopForRegion;
    LayoutUnit logicalBottomForRegion;

    // extend the first region top to contain everything up to its logical height
    if (region->isFirstRegion())
        logicalTopForRegion = LayoutUnit::min();
    else
        logicalTopForRegion =  region->logicalTopForFlowThreadContent();

    // extend the last region to contain everything above its y()
    if (region->isLastRegion())
        logicalBottomForRegion = LayoutUnit::max();
    else
        logicalBottomForRegion = region->logicalBottomForFlowThreadContent();

    Vector<Node*> nodes;
    // eliminate the contentNodes that are descendants of other contentNodes
    for (NamedFlowContentNodes::const_iterator it = contentNodes().begin(); it != contentNodes().end(); ++it) {
        Node* node = *it;
        if (!isContainedInNodes(nodes, node))
            nodes.append(node);
    }

    for (size_t i = 0; i < nodes.size(); i++) {
        Node* contentNode = nodes.at(i);
        if (!contentNode->renderer())
            continue;

        RefPtr<Range> range = Range::create(contentNode->document());
        bool foundStartPosition = false;
        bool startsAboveRegion = true;
        bool endsBelowRegion = true;
        bool skipOverOutsideNodes = false;
        Node* lastEndNode = 0;

        for (Node* node = contentNode; node; node = nextNodeInsideContentNode(node, contentNode)) {
            RenderObject* renderer = node->renderer();
            if (!renderer)
                continue;

            LayoutRect boundingBox;
            if (renderer->isRenderInline())
                boundingBox = toRenderInline(renderer)->linesBoundingBox();
            else if (renderer->isText())
                boundingBox = toRenderText(renderer)->linesBoundingBox();
            else {
                boundingBox =  toRenderBox(renderer)->frameRect();
                if (toRenderBox(renderer)->isRelPositioned())
                    boundingBox.move(toRenderBox(renderer)->relativePositionLogicalOffset());
            }

            LayoutUnit offsetTop = renderer->containingBlock()->offsetFromLogicalTopOfFirstPage();
            const LayoutPoint logicalOffsetFromTop(isHorizontalWritingMode() ? LayoutUnit() :  offsetTop,
                isHorizontalWritingMode() ? offsetTop : LayoutUnit());

            boundingBox.moveBy(logicalOffsetFromTop);

            LayoutUnit logicalTopForRenderer = region->logicalTopOfFlowThreadContentRect(boundingBox);
            LayoutUnit logicalBottomForRenderer = region->logicalBottomOfFlowThreadContentRect(boundingBox);

            // if the bounding box of the current element doesn't intersect the region box
            // close the current range only if the start element began inside the region,
            // otherwise just move the start position after this node and keep skipping them until we found a proper start position.
            if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) {
                if (foundStartPosition) {
                    if (!startsAboveRegion) {
                        if (range->intersectsNode(node, IGNORE_EXCEPTION))
                            range->setEndBefore(node, IGNORE_EXCEPTION);
                        rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION));
                        range = Range::create(contentNode->document());
                        startsAboveRegion = true;
                    } else
                        skipOverOutsideNodes = true;
                }
                if (skipOverOutsideNodes)
                    range->setStartAfter(node, IGNORE_EXCEPTION);
                foundStartPosition = false;
                continue;
            }

            // start position
            if (logicalTopForRenderer < logicalTopForRegion && startsAboveRegion) {
                if (renderer->isText()) { // Text crosses region top
                    // for Text elements, just find the last textbox that is contained inside the region and use its start() offset as start position
                    RenderText* textRenderer = toRenderText(renderer);
                    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                        if (offsetTop + box->logicalBottom() < logicalTopForRegion)
                            continue;
                        range->setStart(Position(toText(node), box->start()));
                        startsAboveRegion = false;
                        break;
                    }
                } else { // node crosses region top
                    // for all elements, except Text, just set the start position to be before their children
                    startsAboveRegion = true;
                    range->setStart(Position(node, Position::PositionIsBeforeChildren));
                }
            } else { // node starts inside region
                // for elements that start inside the region, set the start position to be before them. If we found one, we will just skip the others until
                // the range is closed.
                if (startsAboveRegion) {
                    startsAboveRegion = false;
                    range->setStartBefore(node, IGNORE_EXCEPTION);
                }
            }
            skipOverOutsideNodes  = false;
            foundStartPosition = true;

            // end position
            if (logicalBottomForRegion < logicalBottomForRenderer && (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode)))) {
                // for Text elements, just find just find the last textbox that is contained inside the region and use its start()+len() offset as end position
                if (renderer->isText()) { // Text crosses region bottom
                    RenderText* textRenderer = toRenderText(renderer);
                    InlineTextBox* lastBox = 0;
                    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                        if ((offsetTop + box->logicalTop()) < logicalBottomForRegion) {
                            lastBox = box;
                            continue;
                        }
                        ASSERT(lastBox);
                        if (lastBox)
                            range->setEnd(Position(toText(node), lastBox->start() + lastBox->len()));
                        break;
                    }
                    endsBelowRegion = false;
                    lastEndNode = node;
                } else { // node crosses region bottom
                    // for all elements, except Text, just set the start position to be after their children
                    range->setEnd(Position(node, Position::PositionIsAfterChildren));
                    endsBelowRegion = true;
                    lastEndNode = node;
                }
            } else { // node ends inside region
                // for elements that ends inside the region, set the end position to be after them
                // allow this end position to be changed only by other elements that are not descendants of the current end node
                if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) {
                    range->setEndAfter(node, IGNORE_EXCEPTION);
                    endsBelowRegion = false;
                    lastEndNode = node;
                }
            }
        }
        if (foundStartPosition || skipOverOutsideNodes)
            rangeObjects.append(range);
    }
}