Esempio n. 1
0
///////////////////////////////////////////////////////////////////////////////
// AppendThaiCharCluster
//
eastl_size_t Typesetter::AppendThaiCharCluster(eastl_size_t iCharBegin, eastl_size_t charCount, 
                                                 const Char* pCharCluster, eastl_size_t clusterSize)
{
    // The 'iCharBegin' argument refers to the position of pCharCluster in mLineLayout.mCharArray. 
    // There is a possibility that pCharCluster doesn't point to mLineLayout.mCharArray[iCharBegin],
    // as we may be doing some kind of implicit substitution. Thus we have pCharCluster 
    // as an explicit parameter.

    const AnalysisInfo* const pAnalysisInfo = &mLineLayout.mAnalysisInfoArray[iCharBegin];
    GlyphId                   pGlyphIdArray[kMaxThaiGlyphClusterSize];
    eastl_size_t              glyphCount = 0;

    EA_ASSERT(clusterSize && ((iCharBegin + clusterSize) <= mLineLayout.mCharArray.size()));

    if(IsCharThaiLao(*pCharCluster)) // If the cluster is using Thai or Lao script...
        glyphCount = GetThaiGlyphs(iCharBegin, pCharCluster, clusterSize, pGlyphIdArray);
    else
    {
        // In this case we choose glyphs as if doing general glyph shaping. 
        // We just convert the Unicode Chars to glyphs.
        for(eastl_size_t i = 0; i < clusterSize; )
            i += GetGlyphsForChar(pCharCluster + i, clusterSize - i, &mLineLayout.mAnalysisInfoArray[i], pGlyphIdArray + glyphCount, glyphCount);
    }

    AppendGeneralGlyphCluster(iCharBegin, charCount, pCharCluster, charCount, 
                                pGlyphIdArray, glyphCount, pAnalysisInfo->mnBidiLevel);

    PlaceGeneralGlyphCluster(iCharBegin, charCount);

    // As it stands now, all chars must result in at least one glyph, though that 
    // one glyph could be a zero-width space character. Note that the render code
    // has the opportunity to remove such a "no-op" instruction from the display list.
    EA_ASSERT(glyphCount > 0);
    return glyphCount;
}
Esempio n. 2
0
///////////////////////////////////////////////////////////////////////////////
// AppendHebrewCharCluster
//
eastl_size_t Typesetter::AppendHebrewCharCluster(eastl_size_t iCharBegin, eastl_size_t charCount, 
                                                 const Char* pCharCluster, eastl_size_t clusterSize)
{
    // The 'iCharBegin' argument refers to the position of pCharCluster in mLineLayout.mCharArray. 
    // There is a possibility that pCharCluster doesn't point to mLineLayout.mCharArray[iCharBegin],
    // as we may be doing some kind of implicit substitution. Thus we have pCharCluster 
    // as an explicit parameter.

    const AnalysisInfo* const pAnalysisInfo = &mLineLayout.mAnalysisInfoArray[iCharBegin];
    GlyphId                   pGlyphIdArray[kMaxHebrewGlyphClusterSize];
    eastl_size_t              glyphCount = 0;
    eastl_size_t              glyphCountPrev = 0;
    eastl_size_t              charsEaten = 0;

    EA_ASSERT(clusterSize && ((iCharBegin + charCount) <= mLineLayout.mCharArray.size()));
    #ifdef EA_DEBUG
        memset(pGlyphIdArray, 0, sizeof(pGlyphIdArray));
    #endif

    for(eastl_size_t c = 0; c < clusterSize; c += charsEaten)
    {
        if(IsCharHebrew(*pCharCluster))
            charsEaten = GetHebrewGlyphsForChars(pCharCluster + c, clusterSize - c, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount);
        else
            charsEaten = GetGlyphsForChar(pCharCluster + c, clusterSize - c, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount);

        AppendGeneralGlyphCluster(iCharBegin, charCount, pCharCluster + c, charsEaten, 
                                  pGlyphIdArray + glyphCountPrev, glyphCount - glyphCountPrev, 
                                  pAnalysisInfo->mnBidiLevel);

        // Hebrew fonts have decorations that may need to be positionally adjusted.
        // We could do such adjustments with OpenType or with heuristics. The former
        // is more involved and slower but results in the best output. The latter
        // has the opposite characteristics. Right now we do general placement, but 
        // we ought to do some adjustments, such as the case whereby we have lone
        // diacritics that we added a 0x25CC char to.
        PlaceGeneralGlyphCluster(iCharBegin + c, charsEaten);

        glyphCountPrev = glyphCount;
    }

    // As it stands now, all chars must result in at least one glyph, though that 
    // one glyph could be a zero-width space character. Note that the render code
    // has the opportunity to remove such a "no-op" instruction from the display list.
    EA_ASSERT(glyphCount > 0);
    return glyphCount;
}
Esempio n. 3
0
///////////////////////////////////////////////////////////////////////////////
// AppendGeneralCharCluster
//
// charCount is the number of chars referred to in mLineLayout.mCharArray.
// clusterSize is the number of chars in pCharCluster, which itself was 
// generated from mLineLayout.mCharArray and 98% of the time is equivalent.
// The strings will be unequal in the case of character-level substitutions
// such as mirroring, password chars, control chars, etc.
//
// The return value is the number of glyphs generated from pCharCluster/clusterSize.
//
eastl_size_t Typesetter::AppendGeneralCharCluster(eastl_size_t iCharBegin, eastl_size_t charCount, 
                                                  const Char* pCharCluster, eastl_size_t clusterSize)
{
    // The 'iCharBegin' argument refers to the position of pCharCluster in mLineLayout.mCharArray. 
    // There is a possibility that pCharCluster doesn't point to mLineLayout.mCharArray[i],
    // as we may be doing some kind of implicit substitution. Thus we have pCharCluster 
    // as an explicit parameter.

    const AnalysisInfo* const pAnalysisInfo = &mLineLayout.mAnalysisInfoArray[iCharBegin];
    GlyphId                   pGlyphIdArray[kMaxGeneralGlyphClusterSize];
    eastl_size_t              glyphCount = 0;
    eastl_size_t              glyphCountPrev = 0;
    eastl_size_t              charsEaten = 0;

    EA_ASSERT(clusterSize && ((iCharBegin + charCount) <= mLineLayout.mCharArray.size()));
    #ifdef EA_DEBUG
        memset(pGlyphIdArray, 0, sizeof(pGlyphIdArray));
    #endif

    for(eastl_size_t i = 0; i < clusterSize; i += charsEaten)
    {
        // GetGlyphsForChar does a simple char -> glyph 1:1 conversion, through pAnalysisInfo->mpFont (mLineLayout.mAnalysisInfoArray[iCharBegin]). 
        charsEaten = GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, 
                                        pGlyphIdArray + glyphCount, glyphCount);
        EA_ASSERT(charsEaten > 0);

        AppendGeneralGlyphCluster(iCharBegin, charCount, pCharCluster + i, charsEaten, 
                                  pGlyphIdArray + glyphCountPrev, glyphCount - glyphCountPrev, 
                                  pAnalysisInfo->mnBidiLevel);

        PlaceGeneralGlyphCluster(iCharBegin + i, charsEaten);

        glyphCountPrev = glyphCount;
    }

    // As it stands now, all chars must result in at least one glyph, though that 
    // one glyph could be a zero-width space character. Note that the render code
    // has the opportunity to remove such a "no-op" instruction from the display list.
    EA_ASSERT(glyphCount > 0);
    return glyphCount;
}
Esempio n. 4
0
///////////////////////////////////////////////////////////////////////////////
// AppendHangulCharCluster
//
eastl_size_t Typesetter::AppendHangulCharCluster(eastl_size_t iCharBegin, eastl_size_t charCount, 
                                                 const Char* pCharCluster, eastl_size_t clusterSize, int clusterType)
{
    // The 'iCharBegin' argument refers to the position of pCharCluster in mLineLayout.mCharArray. 
    // There is a possibility that pCharCluster doesn't point to mLineLayout.mCharArray[iCharBegin],
    // as we may be doing some kind of implicit substitution. Thus we have pCharCluster 
    // as an explicit parameter.

    const AnalysisInfo* const pAnalysisInfo = &mLineLayout.mAnalysisInfoArray[iCharBegin];
    GlyphId                   pGlyphIdArray[kMaxHangulGlyphClusterSize];
    eastl_size_t              glyphCount = 0;
    eastl_size_t              charsEaten = 0; // Number of chars read from pCharCluster.
    
    EA_ASSERT(clusterSize && ((iCharBegin + charCount) <= mLineLayout.mCharArray.size()));
    #ifdef EA_DEBUG
        memset(pGlyphIdArray, 0, sizeof(pGlyphIdArray));
    #endif

    switch(clusterType)
    {
        case kHangulClusterTypeJamo:
        {
            const Char cTone       = pCharCluster[clusterSize - 1];
            const bool bAppendTone = IsTone(cTone);
            int        syllableLength;
            Char       c;

            if(bAppendTone)
                --clusterSize; // Pretend it isn't there for now.

            if((clusterSize >= 3) && IsLSyllable(pCharCluster[0]) && IsVSyllable(pCharCluster[1]) && IsTSyllable(pCharCluster[2]))
                syllableLength = 3;
            else if((clusterSize >= 2) && IsLSyllable(pCharCluster[0]) && IsVSyllable(pCharCluster[1]))
                syllableLength = 2;
            else
                syllableLength = 0;

            if(syllableLength)
            {
                if(syllableLength == 3)
                    c = GetSyllableLVT(pCharCluster[0], pCharCluster[1], pCharCluster[2]);
                else
                    c = GetSyllableLV(pCharCluster[0], pCharCluster[1]);

                GetGlyphsForChar(&c, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount);

                charsEaten += syllableLength;
            }

            // If there are any other chars to shape (usually there aren't), just append them.
            for(eastl_size_t i = charsEaten; i < clusterSize; i += charsEaten)
            {
                if((pCharCluster[i] != kJamoLFiller) &&  // Outright ignore filler chars.
                   (pCharCluster[i] != kJamoVFiller))
                {
                    // The font selection in use had better have the desired glyphs or 
                    // else we will be displaying a lot of square boxes on the screen.
                    charsEaten += GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, 
                                                    pGlyphIdArray + glyphCount, glyphCount);
                }
                else
                    ++charsEaten;
            }

            EA_ASSERT(glyphCount > 0); // Do we have just a single Jamo filler char?
            if(glyphCount == 0)
            {
                const Char cHangulFiller = 0x3164; // 0x3164 is the Hangul filler char. It's just blank like a space char.

                charsEaten += GetGlyphsForChar(&cHangulFiller, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount, L"\x25CB _o", 4);
            }

            if(bAppendTone)
            {
                charsEaten += GetGlyphsForChar(&cTone, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount, 
                                                 (cTone == kHangulTone1) ? L"\x00b7" : L":", 1);
            }

            break;
        }

        case kHangulClusterTypeTone: // Standalone tone with no preceeding base glyph.
        {
            // We prepend a character which is a circle implemented with dotted lines. 
            // It is the Unicode standard for generic base character to be represented
            // by such a dotted circle. It is a defacto standard that we prepend such 
            // a character when none is provided. It makes the text look more sensible.
            const Char cDottedCircle = 0x25CC;

            for(eastl_size_t i = charsEaten; i < clusterSize; i += charsEaten) // clusterSize should usually (always?) be just one.
            {
                // Note that in practice we're going to need to put the tone to the 
                // left of the glyph, though here we stuff it afterwards. What we have
                // here won't do. Also, the tone chars ideally have a zero advance,
                // but the fallbacks definitely do not. 

                // We draw the tone, using fallback characters if the tone char isn't present.
                charsEaten += GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, 
                                               pGlyphIdArray + glyphCount, glyphCount, 
                                               (pCharCluster[i] == kHangulTone1) ? L"\x00b7" : L":", 1);

                // Append a dotted-circle glyph, with a fallback of some other glyphs.
                GetGlyphsForChar(&cDottedCircle, 1, pAnalysisInfo, 
                                  pGlyphIdArray + glyphCount, glyphCount, L"\x25CB _o", 4);
            }

            break;
        }

        case kHangulClusterTypeUnicode:
        {
            // We just convert the Unicode Chars to glyphs.
            for(eastl_size_t i = charsEaten; i < clusterSize; i += charsEaten)
            {
                charsEaten += GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, 
                                                pGlyphIdArray + glyphCount, glyphCount);
            }
            break;
        }

        default:
            EA_FAIL_MESSAGE("Typesetter::AppendHangulCharCluster: Unknown cluster type.");
            break;
    }

    // Assert that all of the passed in cluster was processed.
    EA_ASSERT(charsEaten == clusterSize);

    // We use the general glyph append function.
    AppendGeneralGlyphCluster(iCharBegin, charCount, pCharCluster, charsEaten, pGlyphIdArray, glyphCount, pAnalysisInfo->mnBidiLevel);

    // We use the general glyph placement function.
    PlaceGeneralGlyphCluster(iCharBegin, charsEaten);

    // As it stands now, all chars must result in at least one glyph, though that 
    // one glyph could be a zero-width space character. Note that the render code
    // has the opportunity to remove such a "no-op" instruction from the display list.
    EA_ASSERT(glyphCount > 0);
    return glyphCount;
}