void setGlyphXPositions(bool isRTL)
    {
        double position = 0;
        // logClustersIndex indexes logClusters for the first (or last when
        // RTL) codepoint of the current glyph.  Each time we advance a glyph,
        // we skip over all the codepoints that contributed to the current
        // glyph.
        unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0;

        for (int iter = 0; iter < m_item.num_glyphs; ++iter) {
            // Glyphs are stored in logical order, but for layout purposes we
            // always go left to right.
            int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;

            m_glyphs16[i] = m_item.glyphs[i];
            double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
            m_xPositions[i] = m_offsetX + position + offsetX;

            double advance = truncateFixedPointToInteger(m_item.advances[i]);
            // The first half of the conjuction works around the case where
            // output glyphs aren't associated with any codepoints by the
            // clusters log.
            if (logClustersIndex < m_item.item.length
                && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) {
                advance += m_wordSpacingAdjustment;

                if (m_padding > 0) {
                    unsigned toPad = roundf(m_padPerWordBreak + m_padError);
                    m_padError += m_padPerWordBreak - toPad;

                    if (m_padding < toPad)
                        toPad = m_padding;
                    m_padding -= toPad;
                    advance += toPad;
                }
            }

            // We would like to add m_letterSpacing after each cluster, but I
            // don't know where the cluster information is. This is typically
            // fine for Roman languages, but breaks more complex languages
            // terribly.
            // advance += m_letterSpacing;

            if (isRTL) {
                while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
                    logClustersIndex--;
            } else {
                while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i)
                    logClustersIndex++;
            }

            position += advance;
        }

        m_pixelWidth = position;
        m_offsetX += m_pixelWidth;
    }
Beispiel #2
0
// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const FloatPoint& point, int height,
                                            int from, int to) const
{
    int fromX = -1, toX = -1;
    ComplexTextController controller(run, 0, 0, this);
    controller.setWordSpacingAdjustment(wordSpacing());
    controller.setLetterSpacingAdjustment(letterSpacing());
    controller.setPadding(run.expansion());
    if (run.rtl()) {
        // See FIXME in drawComplexText.
        controller.reset(controller.widthOfFullRun());
        controller.setPadding(run.expansion());
    }

    // Iterate through the script runs in logical order, searching for the run covering the positions of interest.
    while (controller.nextScriptRun() && (fromX == -1 || toX == -1)) {
        if (fromX == -1 && from >= 0 && static_cast<unsigned>(from) < controller.numCodePoints()) {
            // |from| is within this script run. So we index the clusters log to
            // find which glyph this code-point contributed to and find its x
            // position.
            int glyph = controller.logClusters()[from];
            fromX = controller.positions()[glyph].x();
            if (controller.rtl())
                fromX += truncateFixedPointToInteger(controller.advances()[glyph]);
        } else
            from -= controller.numCodePoints();

        if (toX == -1 && to >= 0 && static_cast<unsigned>(to) < controller.numCodePoints()) {
            int glyph = controller.logClusters()[to];
            toX = controller.positions()[glyph].x();
            if (controller.rtl())
                toX += truncateFixedPointToInteger(controller.advances()[glyph]);
        } else
            to -= controller.numCodePoints();
    }

    // The position in question might be just after the text.
    if (fromX == -1)
        fromX = controller.offsetX();
    if (toX == -1)
        toX = controller.offsetX();

    ASSERT(fromX != -1 && toX != -1);

    if (fromX < toX)
        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);

    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}
Beispiel #3
0
static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x)
{
    const HB_Fixed* advances = walker.advances();
    int glyphIndex;
    if (walker.rtl()) {
        for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) {
            if (x < truncateFixedPointToInteger(advances[glyphIndex]))
                break;
            x -= truncateFixedPointToInteger(advances[glyphIndex]);
        }
    } else {
        for (glyphIndex = 0; glyphIndex < walker.length(); ++glyphIndex) {
            if (x < truncateFixedPointToInteger(advances[glyphIndex]))
                break;
            x -= truncateFixedPointToInteger(advances[glyphIndex]);
        }
    }

    return glyphIndex;
}
Beispiel #4
0
void ComplexTextController::setGlyphPositions(bool isRTL)
{
    const double rtlFlip = isRTL ? -1 : 1;
    double position = 0;

    // logClustersIndex indexes logClusters for the first codepoint of the current glyph.
    // Each time we advance a glyph, we skip over all the codepoints that contributed to the current glyph.
    int logClustersIndex = 0;

    // Iterate through the glyphs in logical order, flipping for RTL where necessary.
    // Glyphs are positioned starting from m_offsetX; in RTL mode they go leftwards from there.
    for (size_t i = 0; i < m_item.num_glyphs; ++i) {
        while (static_cast<unsigned>(logClustersIndex) < m_item.item.length && m_item.log_clusters[logClustersIndex] < i)
            logClustersIndex++;

        // If the current glyph is just after a space, add in the word spacing.
        position += determineWordBreakSpacing(logClustersIndex);

        m_glyphs16[i] = m_item.glyphs[i];
        double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
        double offsetY = truncateFixedPointToInteger(m_item.offsets[i].y);
        double advance = truncateFixedPointToInteger(m_item.advances[i]);
        if (isRTL)
            offsetX -= advance;

        m_positions[i].set(m_offsetX + (position * rtlFlip) + offsetX,
                           m_startingY + offsetY);

        if (m_currentFontData->isZeroWidthSpaceGlyph(m_glyphs16[i]))
            continue;

        // At the end of each cluster, add in the letter spacing.
        if (i + 1 == m_item.num_glyphs || m_item.attributes[i + 1].clusterStart)
            position += m_letterSpacing;

        position += advance;
    }
    m_pixelWidth = std::max(position, 0.0);
    m_offsetX += m_pixelWidth * rtlFlip;
}
Beispiel #5
0
FloatRect ComplexTextController::selectionRect(const FloatPoint& point, int height, int from, int to)
{
    int fromX = -1, toX = -1;
    // Iterate through the script runs in logical order, searching for the run covering the positions of interest.
    while (nextScriptRun() && (fromX == -1 || toX == -1)) {
        if (fromX == -1 && from >= 0 && static_cast<unsigned>(from) < numCodePoints()) {
            // |from| is within this script run. So we index the clusters log to
            // find which glyph this code-point contributed to and find its x
            // position.
            int glyph = m_item.log_clusters[from];
            fromX = positions()[glyph].x();
            if (rtl())
                fromX += truncateFixedPointToInteger(m_item.advances[glyph]);
        } else
            from -= numCodePoints();

        if (toX == -1 && to >= 0 && static_cast<unsigned>(to) < numCodePoints()) {
            int glyph = m_item.log_clusters[to];
            toX = positions()[glyph].x();
            if (rtl())
                toX += truncateFixedPointToInteger(m_item.advances[glyph]);
        } else
            to -= numCodePoints();
    }

    // The position in question might be just after the text.
    if (fromX == -1)
        fromX = offsetX();
    if (toX == -1)
        toX = offsetX();

    ASSERT(fromX != -1 && toX != -1);

    if (fromX < toX)
        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);

    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}
Beispiel #6
0
static int glyphIndexForXPositionInScriptRun(const ComplexTextController& controller, int targetX)
{
    // Iterate through the glyphs in logical order, seeing whether targetX falls between the previous
    // position and halfway through the current glyph.
    // FIXME: this code probably belongs in ComplexTextController.
    int lastX = controller.offsetX() - (controller.rtl() ? -controller.width() : controller.width());
    for (int glyphIndex = 0; static_cast<unsigned>(glyphIndex) < controller.length(); ++glyphIndex) {
        int advance = truncateFixedPointToInteger(controller.advances()[glyphIndex]);
        int nextX = static_cast<int>(controller.positions()[glyphIndex].x()) + advance / 2;
        if (std::min(nextX, lastX) <= targetX && targetX <= std::max(nextX, lastX))
            return glyphIndex;
        lastX = nextX;
    }

    return controller.length() - 1;
}
Beispiel #7
0
    void setGlyphXPositions(bool isRTL)
    {
        m_pixelWidth = 0;
        for (unsigned i = 0; i < m_item.num_glyphs; ++i) {
            int index;
            if (isRTL)
                index = m_item.num_glyphs - (i + 1);
            else
                index = i;

            m_glyphs16[i] = m_item.glyphs[i];
            m_xPositions[index] = m_offsetX + m_pixelWidth;
            m_pixelWidth += truncateFixedPointToInteger(m_item.advances[index]);
        }
        m_offsetX += m_pixelWidth;
    }
Beispiel #8
0
// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const IntPoint& point, int height,
                                            int from, int to) const
{
    int fromX = -1, toX = -1, fromAdvance = -1, toAdvance = -1;
    TextRunWalker walker(run, 0, this);

    // Base will point to the x offset for the current script run. Note that, in
    // the LTR case, width will be 0.
    int base = walker.rtl() ? walker.widthOfFullRun() : 0;
    const int leftEdge = base;

    // We want to enumerate the script runs in code point order in the following
    // code. This call also resets |walker|.
    walker.setBackwardsIteration(false);

    while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) {
        // TextRunWalker will helpfully accululate the x offsets for different
        // script runs for us. For this code, however, we always want the x offsets
        // to start from zero so we call this before each script run.
        walker.setXOffsetToZero();

        if (walker.rtl())
            base -= walker.width();

        if (fromX == -1 && from < walker.numCodePoints()) {
            // |from| is within this script run. So we index the clusters log to
            // find which glyph this code-point contributed to and find its x
            // position.
            int glyph = walker.logClusters()[from];
            fromX = base + walker.xPositions()[glyph];
            fromAdvance = walker.advances()[glyph];
        } else
            from -= walker.numCodePoints();

        if (toX == -1 && to < walker.numCodePoints()) {
            int glyph = walker.logClusters()[to];
            toX = base + walker.xPositions()[glyph];
            toAdvance = walker.advances()[glyph];
        } else
            to -= walker.numCodePoints();

        if (!walker.rtl())
            base += walker.width();
    }

    // The position in question might be just after the text.
    const int rightEdge = base;
    if (fromX == -1 && !from)
        fromX = leftEdge;
    else if (walker.rtl())
       fromX += truncateFixedPointToInteger(fromAdvance);

    if (toX == -1 && !to)
        toX = rightEdge;
    else if (!walker.rtl())
        toX += truncateFixedPointToInteger(toAdvance);

    ASSERT(fromX != -1 && toX != -1);

    if (fromX < toX)
        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);

    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}