示例#1
0
void GraphicsContext::drawBidiText(const FontCascade& font, const TextRun& run, const FloatPoint& point, FontCascade::CustomFontNotReadyAction customFontNotReadyAction)
{
    if (paintingDisabled())
        return;

    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
    bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));

    // FIXME: This ownership should be reversed. We should pass BidiRunList
    // to BidiResolver in createBidiRunsForLine.
    BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));

    if (!bidiRuns.runCount())
        return;

    FloatPoint currPoint = point;
    BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    while (bidiRun) {
        TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
        bool isRTL = bidiRun->level() % 2;
        subrun.setDirection(isRTL ? RTL : LTR);
        subrun.setDirectionalOverride(bidiRun->dirOverride(false));

        float width = font.drawText(*this, subrun, currPoint, 0, -1, customFontNotReadyAction);
        currPoint.move(width, 0);

        bidiRun = bidiRun->next();
    }

    bidiRuns.deleteRuns();
}
示例#2
0
void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
{
    if (paintingDisabled())
        return;

    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
    bidiResolver.setPosition(TextRunIterator(&run, 0));

    // FIXME: This ownership should be reversed. We should pass BidiRunList
    // to BidiResolver in createBidiRunsForLine.
    BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
    if (!bidiRuns.runCount())
        return;

    FloatPoint currPoint = point;
    BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    while (bidiRun) {
        TextRun subrun = run;
        subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
        bool isRTL = bidiRun->level() % 2;
        subrun.setDirection(isRTL ? RTL : LTR);
        subrun.setDirectionalOverride(bidiRun->dirOverride(false));

        font.drawText(this, subrun, currPoint);

        bidiRun = bidiRun->next();
        // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
        if (bidiRun)
            currPoint.move(font.width(subrun), 0);
    }

    bidiRuns.deleteRuns();
}
void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
{
    if (paintingDisabled())
        return;

    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;

    bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride())));

    bidiResolver.setPosition(TextRunIterator(&run, 0));
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));

    if (!bidiResolver.runCount())
        return;

    FloatPoint currPoint = point;
    BidiCharacterRun* bidiRun = bidiResolver.firstRun();
    while (bidiRun) {

        TextRun subrun = run;
        subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
        subrun.setRTL(bidiRun->level() % 2);
        subrun.setDirectionalOverride(bidiRun->dirOverride(false));

        font.drawText(this, subrun, currPoint);

        bidiRun = bidiRun->next();
        // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
        if (bidiRun)
            currPoint.move(font.floatWidth(subrun), 0.f);
    }

    bidiResolver.deleteRuns();
}
示例#4
0
void LayoutSVGInlineText::updateMetricsList(bool& lastCharacterWasWhiteSpace)
{
    m_metrics.clear();

    if (!textLength())
        return;

    TextRun run = constructTextRun(*this, 0, textLength(), styleRef().direction());
    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    bool bidiOverride = isOverride(styleRef().unicodeBidi());
    BidiStatus status(LTR, bidiOverride);
    if (run.is8Bit() || bidiOverride) {
        WTF::Unicode::CharDirection direction = WTF::Unicode::LeftToRight;
        // If BiDi override is in effect, use the specified direction.
        if (bidiOverride && !styleRef().isLeftToRightDirection())
            direction = WTF::Unicode::RightToLeft;
        bidiRuns.addRun(new BidiCharacterRun(0, run.charactersLength(), status.context.get(), direction));
    } else {
        status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
        bidiResolver.setStatus(status);
        bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
        const bool hardLineBreak = false;
        const bool reorderRuns = false;
        bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()), NoVisualOverride, hardLineBreak, reorderRuns);
    }

    for (const BidiCharacterRun* bidiRun = bidiRuns.firstRun(); bidiRun; bidiRun = bidiRun->next()) {
        TextRun subRun = constructTextRun(*this, bidiRun->start(), bidiRun->stop() - bidiRun->start(),
            bidiRun->direction());
        addMetricsFromRun(subRun, lastCharacterWasWhiteSpace);
    }

    bidiResolver.runs().deleteRuns();
}
示例#5
0
TextDirection directionForRun(TextRun& run, bool& hasStrongDirectionality)
{
    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
    bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
    return bidiResolver.determineParagraphDirectionality(&hasStrongDirectionality);
}
TextDirection determineParagraphDirectionality(const TextRun& textRun, bool* hasStrongDirectionality = 0)
{
    BidiResolver<TextRunIterator, BidiCharacterRun> resolver;
    resolver.setStatus(BidiStatus(LTR, false));
    resolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
    return resolver.determineParagraphDirectionality(hasStrongDirectionality);
}
示例#7
0
// Almost the same as determineDirectionality in core/html/HTMLElement.cpp, but
// that one uses a "plain" TextRunIterator (which only checks for '\n').
static TextDirection determineDirectionality(const String& value, bool& hasStrongDirectionality)
{
    TextRun run(value);
    BidiResolver<VTTTextRunIterator, BidiCharacterRun> bidiResolver;
    bidiResolver.setStatus(BidiStatus(LTR, false));
    bidiResolver.setPositionIgnoringNestedIsolates(VTTTextRunIterator(&run, 0));
    return bidiResolver.determineParagraphDirectionality(&hasStrongDirectionality);
}
TEST(BidiResolver, Basic)
{
    bool hasStrongDirectionality;
    String value("foo");
    TextRun run(value);
    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
    bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
    TextDirection direction = bidiResolver.determineParagraphDirectionality(&hasStrongDirectionality);
    EXPECT_TRUE(hasStrongDirectionality);
    EXPECT_EQ(LTR, direction);
}
示例#9
0
TextDirection directionForRun(TextRun& run, bool* hasStrongDirectionality)
{
    if (!hasStrongDirectionality) {
        // 8bit is Latin-1 and therefore is always LTR.
        if (run.is8Bit())
            return LTR;

        // length == 1 for more than 90% of cases of width() for CJK text.
        if (run.length() == 1 && U16_IS_SINGLE(run.characters16()[0]))
            return directionForCharacter(run.characters16()[0]);
    }

    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
    bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
    return bidiResolver.determineParagraphDirectionality(hasStrongDirectionality);
}
示例#10
0
void SVGTextMetricsCalculator::setupBidiRuns()
{
    RenderStyle* style = m_text->style();
    m_textDirection = style->direction();
    if (isOverride(style->unicodeBidi()))
        return;

    BidiStatus status(LTR, false);
    status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
    m_bidiResolver.setStatus(status);
    m_bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&m_run, 0));
    const bool hardLineBreak = false;
    const bool reorderRuns = false;
    m_bidiResolver.createBidiRunsForLine(TextRunIterator(&m_run, m_run.length()), NoVisualOverride, hardLineBreak, reorderRuns);
    BidiRunList<BidiCharacterRun>& bidiRuns = m_bidiResolver.runs();
    m_bidiRun = bidiRuns.firstRun();
}
// ReverseBidi is a trimmed-down version of GraphicsContext::drawBidiText()
void ReverseBidi(UChar* chars, int len) {
    using namespace WTF::Unicode;
    WTF::Vector<UChar> result;
    result.reserveCapacity(len);
    TextRun run(chars, len);
    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    bidiResolver.setStatus(BidiStatus(LeftToRight, LeftToRight, LeftToRight,
        BidiContext::create(0, LeftToRight, false)));
    bidiResolver.setPosition(TextRunIterator(&run, 0));
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, len));
    if (!bidiRuns.runCount())
        return;
    BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    while (bidiRun) {
        int bidiStart = bidiRun->start();
        int bidiStop = bidiRun->stop();
        int size = result.size();
        int bidiCount = bidiStop - bidiStart;
        result.append(chars + bidiStart, bidiCount);
        if (bidiRun->level() % 2) {
            UChar* start = &result[size];
            UChar* end = start + bidiCount;
            // reverse the order of any RTL substrings
            while (start < end) {
                UChar temp = *start;
                *start++ = *--end;
                *end = temp;
            }
            start = &result[size];
            end = start + bidiCount - 1;
            // if the RTL substring had a surrogate pair, restore its order
            while (start < end) {
                UChar trail = *start++;
                if (!U16_IS_SURROGATE(trail))
                    continue;
                start[-1] = *start; // lead
                *start++ = trail;
            }
        }
        bidiRun = bidiRun->next();
    }
    bidiRuns.deleteRuns();
    memcpy(chars, &result[0], len * sizeof(UChar));
}
示例#12
0
float GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction, BidiStatus* status, int length)
#endif
{
    if (paintingDisabled())
#if !PLATFORM(IOS)
        return;
#else
        return 0;
#endif

    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
#if !PLATFORM(IOS)
    bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
#else
    bidiResolver.setStatus(status ? *status : BidiStatus(run.direction(), run.directionalOverride()));
#endif
    bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));

    // FIXME: This ownership should be reversed. We should pass BidiRunList
    // to BidiResolver in createBidiRunsForLine.
    BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
#if !PLATFORM(IOS)
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
#else
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, length < 0 ? run.length() : length));
#endif    
    if (!bidiRuns.runCount())
#if !PLATFORM(IOS)
        return;
#else
        return 0;
#endif

    FloatPoint currPoint = point;
    BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    while (bidiRun) {
        TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
        bool isRTL = bidiRun->level() % 2;
        subrun.setDirection(isRTL ? RTL : LTR);
        subrun.setDirectionalOverride(bidiRun->dirOverride(false));

#if !PLATFORM(IOS)
        font.drawText(this, subrun, currPoint, 0, -1, customFontNotReadyAction);

        bidiRun = bidiRun->next();
        // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
        if (bidiRun)
            currPoint.move(font.width(subrun), 0);
#else
        float width = font.drawText(this, subrun, currPoint, 0, -1, customFontNotReadyAction);
        currPoint.move(width, 0);

        bidiRun = bidiRun->next();
#endif
    }

#if PLATFORM(IOS)
    if (status)
        *status = bidiResolver.status();
#endif
    bidiRuns.deleteRuns();

#if PLATFORM(IOS)
    return currPoint.x() - static_cast<float>(point.x());
#endif
}
void BidiTestRunner::runTest(const std::basic_string<UChar>& input, const std::vector<int>& expectedOrder,
    const std::vector<int>& expectedLevels, bidi_test::ParagraphDirection paragraphDirection,
    const std::string& line, size_t lineNumber)
{
    if (!m_skippedCodePoints.empty()) {
        for (size_t i = 0; i < input.size(); i++) {
            if (m_skippedCodePoints.count(input[i])) {
                m_testsSkipped++;
                return;
            }
        }
    }

    m_testsRun++;

    TextRun textRun(input.data(), input.size());
    switch (paragraphDirection) {
    case bidi_test::DirectionAutoLTR:
        textRun.setDirection(determineParagraphDirectionality(textRun));
        break;
    case bidi_test::DirectionLTR:
        textRun.setDirection(LTR);
        break;
    case bidi_test::DirectionRTL:
        textRun.setDirection(RTL);
        break;
    }
    BidiResolver<TextRunIterator, BidiCharacterRun> resolver;
    resolver.setStatus(BidiStatus(textRun.direction(), textRun.directionalOverride()));
    resolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));

    BidiRunList<BidiCharacterRun>& runs = resolver.runs();
    resolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()));

    std::ostringstream errorContext;
    errorContext << ", line " << lineNumber << " \"" << line << "\"";
    errorContext << " context: " << bidi_test::nameFromParagraphDirection(paragraphDirection);

    std::vector<int> actualOrder;
    std::vector<int> actualLevels;
    actualLevels.assign(input.size(), -1);
    BidiCharacterRun* run = runs.firstRun();
    while (run) {
        // Blink's UBA just makes runs, the actual ordering of the display of characters
        // is handled later in our pipeline, so we fake it here:
        bool reversed = run->reversed(false);
        ASSERT(run->stop() >= run->start());
        size_t length = run->stop() - run->start();
        for (size_t i = 0; i < length; i++) {
            int inputIndex = reversed ? run->stop() - i - 1 : run->start() + i;
            if (!isNonRenderedCodePoint(input[inputIndex]))
                actualOrder.push_back(inputIndex);
            // BidiTest.txt gives expected level data in the order of the original input.
            actualLevels[inputIndex] = run->level();
        }
        run = run->next();
    }

    if (expectedOrder.size() != actualOrder.size()) {
        m_ignoredCharFailures++;
        EXPECT_EQ(expectedOrder.size(), actualOrder.size()) << errorContext.str();
    } else if (expectedOrder != actualOrder) {
        m_orderFailures++;
        printf("ORDER %s%s\n", diffString(actualOrder, expectedOrder).c_str(), errorContext.str().c_str());
    }

    if (expectedLevels.size() != actualLevels.size()) {
        m_ignoredCharFailures++;
        EXPECT_EQ(expectedLevels.size(), actualLevels.size()) << errorContext.str();
    } else {
        for (size_t i = 0; i < expectedLevels.size(); i++) {
            // level == -1 means the level should be ignored.
            if (expectedLevels[i] == actualLevels[i] || expectedLevels[i] == -1)
                continue;

            printf("LEVELS %s%s\n", diffString(actualLevels, expectedLevels).c_str(), errorContext.str().c_str());
            m_levelFailures++;
            break;
        }
    }
    runs.deleteRuns();
}