⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 svginlinetextbox.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/** * This file is part of the DOM implementation for KDE. * * Copyright (C) 2007 Rob Buis <buis@kde.org> *           (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#if ENABLE(SVG)#include "SVGInlineTextBox.h"#include "Document.h"#include "Editor.h"#include "Frame.h"#include "GraphicsContext.h"#include "InlineFlowBox.h"#include "Range.h"#include "SVGPaintServer.h"#include "SVGRootInlineBox.h"#include "Text.h"#include <float.h>using std::max;namespace WebCore {SVGInlineTextBox::SVGInlineTextBox(RenderObject* obj)    : InlineTextBox(obj)    , m_height(0){}int SVGInlineTextBox::selectionTop(){    return m_y;} int SVGInlineTextBox::selectionHeight(){    return m_height;}SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const{    // Find associated root inline box    InlineFlowBox* parentBox = parent();    while (parentBox && !parentBox->isRootInlineBox())        parentBox = parentBox->parent();    ASSERT(parentBox);    ASSERT(parentBox->isRootInlineBox());    if (!parentBox->isSVGRootInlineBox())        return 0;    return static_cast<SVGRootInlineBox*>(parentBox);}float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const{    ASSERT(style);    return style->font().floatWidth(svgTextRunForInlineTextBox(textRenderer()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName);}float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int, int) const{    // This is just a guess, and the only purpose of this function is to centralize this hack.    // In real-life top-top-bottom scripts this won't be enough, I fear.    return style->font().ascent() + style->font().descent();}FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int offset, const SVGChar& svgChar) const{    const Font& font = style->font();    // Take RTL text into account and pick right glyph width/height.    float glyphWidth = 0.0f;    // FIXME: account for multi-character glyphs    int charsConsumed;    String glyphName;    if (direction() == LTR)        glyphWidth = calculateGlyphWidth(style, offset, 0, charsConsumed, glyphName);    else        glyphWidth = calculateGlyphWidth(style, start() + end() - offset, 0, charsConsumed, glyphName);    float x1 = svgChar.x;    float x2 = svgChar.x + glyphWidth;    float y1 = svgChar.y - font.ascent();    float y2 = svgChar.y + font.descent();    FloatRect glyphRect(x1, y1, x2 - x1, y2 - y1);    // Take per-character transformations into account    TransformationMatrix ctm = svgChar.characterTransform();    if (!ctm.isIdentity())        glyphRect = ctm.mapRect(glyphRect);    return glyphRect;}// Helper class for closestCharacterToPosition()struct SVGInlineTextBoxClosestCharacterToPositionWalker {    SVGInlineTextBoxClosestCharacterToPositionWalker(int x, int y)        : m_character(0)        , m_distance(FLT_MAX)        , m_x(x)        , m_y(y)        , m_offsetOfHitCharacter(0)    {    }    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,                              const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)    {        RenderStyle* style = textBox->textRenderer()->style();        Vector<SVGChar>::iterator closestCharacter = 0;        unsigned int closestOffset = UINT_MAX;        for (Vector<SVGChar>::iterator it = start; it != end; ++it) {            if (it->isHidden())                continue;            unsigned int newOffset = textBox->start() + (it - start) + startOffset;            FloatRect glyphRect = chunkCtm.mapRect(textBox->calculateGlyphBoundaries(style, newOffset, *it));            // Take RTL text into account and pick right glyph width/height.            // NOTE: This offset has to be corrected _after_ calling calculateGlyphBoundaries            if (textBox->direction() == RTL)                newOffset = textBox->start() + textBox->end() - newOffset;            // Calculate distances relative to the glyph mid-point. I hope this is accurate enough.            float xDistance = glyphRect.x() + glyphRect.width() / 2.0f - m_x;            float yDistance = glyphRect.y() - glyphRect.height() / 2.0f - m_y;            float newDistance = sqrtf(xDistance * xDistance + yDistance * yDistance);            if (newDistance <= m_distance) {                m_distance = newDistance;                closestOffset = newOffset;                closestCharacter = it;            }        }        if (closestOffset != UINT_MAX) {            // Record current chunk, if it contains the current closest character next to the mouse.            m_character = closestCharacter;            m_offsetOfHitCharacter = closestOffset;        }    }    SVGChar* character() const    {        return m_character;    }    int offsetOfHitCharacter() const    {        if (!m_character)            return 0;        return m_offsetOfHitCharacter;    }private:    Vector<SVGChar>::iterator m_character;    float m_distance;    int m_x;    int m_y;    int m_offsetOfHitCharacter;};// Helper class for selectionRect()struct SVGInlineTextBoxSelectionRectWalker {    SVGInlineTextBoxSelectionRectWalker()    {    }    void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,                              const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)    {        RenderStyle* style = textBox->textRenderer()->style();        for (Vector<SVGChar>::iterator it = start; it != end; ++it) {            if (it->isHidden())                continue;            unsigned int newOffset = textBox->start() + (it - start) + startOffset;            m_selectionRect.unite(textBox->calculateGlyphBoundaries(style, newOffset, *it));        }        m_selectionRect = chunkCtm.mapRect(m_selectionRect);    }    FloatRect selectionRect() const    {        return m_selectionRect;    }private:    FloatRect m_selectionRect;};SVGChar* SVGInlineTextBox::closestCharacterToPosition(int x, int y, int& offsetOfHitCharacter) const{    SVGRootInlineBox* rootBox = svgRootInlineBox();    if (!rootBox)        return 0;    SVGInlineTextBoxClosestCharacterToPositionWalker walkerCallback(x, y);    SVGTextChunkWalker<SVGInlineTextBoxClosestCharacterToPositionWalker> walker(&walkerCallback, &SVGInlineTextBoxClosestCharacterToPositionWalker::chunkPortionCallback);    rootBox->walkTextChunks(&walker, this);    offsetOfHitCharacter = walkerCallback.offsetOfHitCharacter();    return walkerCallback.character();}bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& closestOffsetInBox) const{    int offsetOfHitCharacter = 0;    SVGChar* charAtPosPtr = closestCharacterToPosition(x, y, offsetOfHitCharacter);    if (!charAtPosPtr)        return false;    SVGChar& charAtPos = *charAtPosPtr;    RenderStyle* style = textRenderer()->style(m_firstLine);    FloatRect glyphRect = calculateGlyphBoundaries(style, offsetOfHitCharacter, charAtPos);    // FIXME: Why?    if (direction() == RTL)        offsetOfHitCharacter++;    // The caller actually the closest offset before/after the hit char    // closestCharacterToPosition returns us offsetOfHitCharacter.    closestOffsetInBox = offsetOfHitCharacter;    // FIXME: (bug 13910) This code does not handle bottom-to-top/top-to-bottom vertical text.    // Check whether y position hits the current character     if (y < charAtPos.y - glyphRect.height() || y > charAtPos.y)        return false;    // Check whether x position hits the current character    if (x < charAtPos.x) {        if (closestOffsetInBox > 0 && direction() == LTR)            return true;        else if (closestOffsetInBox < (int) end() && direction() == RTL)            return true;        return false;    }    // Adjust the closest offset to after the char if x was after the char midpoint    if (x >= charAtPos.x + glyphRect.width() / 2.0)        closestOffsetInBox += direction() == RTL ? -1 : 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -