void TestSVGTypeface::exportTtxCommon()

in tools/fonts/TestSVGTypeface.cpp [444:774]


void TestSVGTypeface::exportTtxCommon(SkWStream*                out,
                                      const char*               type,
                                      const TArray<GlyfInfo>* glyfInfo) const {
    int totalGlyphs = fGlyphCount;
    out->writeText("  <GlyphOrder>\n");
    for (int i = 0; i < fGlyphCount; ++i) {
        out->writeText("    <GlyphID name=\"glyf");
        out->writeHexAsText(i, 4);
        out->writeText("\"/>\n");
    }
    if (glyfInfo) {
        for (int i = 0; i < fGlyphCount; ++i) {
            for (int j = 0; j < (*glyfInfo)[i].fLayers.size(); ++j) {
                out->writeText("    <GlyphID name=\"glyf");
                out->writeHexAsText(i, 4);
                out->writeText("l");
                out->writeHexAsText(j, 4);
                out->writeText("\"/>\n");
                ++totalGlyphs;
            }
        }
    }
    out->writeText("  </GlyphOrder>\n");

    out->writeText("  <head>\n");
    out->writeText("    <tableVersion value=\"1.0\"/>\n");
    out->writeText("    <fontRevision value=\"1.0\"/>\n");
    out->writeText("    <checkSumAdjustment value=\"0xa9c3274\"/>\n");
    out->writeText("    <magicNumber value=\"0x5f0f3cf5\"/>\n");
    out->writeText("    <flags value=\"00000000 00011011\"/>\n");
    out->writeText("    <unitsPerEm value=\"");
    out->writeDecAsText(fUpem);
    out->writeText("\"/>\n");
    out->writeText("    <created value=\"Thu Feb 15 12:55:49 2018\"/>\n");
    out->writeText("    <modified value=\"Thu Feb 15 12:55:49 2018\"/>\n");
    // TODO: not recalculated for bitmap fonts?
    out->writeText("    <xMin value=\"");
    out->writeScalarAsText(fFontMetrics.fXMin);
    out->writeText("\"/>\n");
    out->writeText("    <yMin value=\"");
    out->writeScalarAsText(-fFontMetrics.fBottom);
    out->writeText("\"/>\n");
    out->writeText("    <xMax value=\"");
    out->writeScalarAsText(fFontMetrics.fXMax);
    out->writeText("\"/>\n");
    out->writeText("    <yMax value=\"");
    out->writeScalarAsText(-fFontMetrics.fTop);
    out->writeText("\"/>\n");

    char macStyle[16] = {
            '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
    if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) {
        macStyle[0xF - 0x0] = '1';  // Bold
    }
    switch (this->fontStyle().slant()) {
        case SkFontStyle::kUpright_Slant: break;
        case SkFontStyle::kItalic_Slant:
            macStyle[0xF - 0x1] = '1';  // Italic
            break;
        case SkFontStyle::kOblique_Slant:
            macStyle[0xF - 0x1] = '1';  // Italic
            break;
        default: SK_ABORT("Unknown slant.");
    }
    if (this->fontStyle().width() <= SkFontStyle::kCondensed_Width) {
        macStyle[0xF - 0x5] = '1';  // Condensed
    } else if (this->fontStyle().width() >= SkFontStyle::kExpanded_Width) {
        macStyle[0xF - 0x6] = '1';  // Extended
    }
    out->writeText("    <macStyle value=\"");
    out->write(macStyle, 8);
    out->writeText(" ");
    out->write(macStyle + 8, 8);
    out->writeText("\"/>\n");
    out->writeText("    <lowestRecPPEM value=\"8\"/>\n");
    out->writeText("    <fontDirectionHint value=\"2\"/>\n");
    out->writeText("    <indexToLocFormat value=\"0\"/>\n");
    out->writeText("    <glyphDataFormat value=\"0\"/>\n");
    out->writeText("  </head>\n");

    out->writeText("  <hhea>\n");
    out->writeText("    <tableVersion value=\"0x00010000\"/>\n");
    out->writeText("    <ascent value=\"");
    out->writeDecAsText(-fFontMetrics.fAscent);
    out->writeText("\"/>\n");
    out->writeText("    <descent value=\"");
    out->writeDecAsText(-fFontMetrics.fDescent);
    out->writeText("\"/>\n");
    out->writeText("    <lineGap value=\"");
    out->writeDecAsText(fFontMetrics.fLeading);
    out->writeText("\"/>\n");
    out->writeText("    <advanceWidthMax value=\"0\"/>\n");
    out->writeText("    <minLeftSideBearing value=\"0\"/>\n");
    out->writeText("    <minRightSideBearing value=\"0\"/>\n");
    out->writeText("    <xMaxExtent value=\"");
    out->writeScalarAsText(fFontMetrics.fXMax - fFontMetrics.fXMin);
    out->writeText("\"/>\n");
    out->writeText("    <caretSlopeRise value=\"1\"/>\n");
    out->writeText("    <caretSlopeRun value=\"0\"/>\n");
    out->writeText("    <caretOffset value=\"0\"/>\n");
    out->writeText("    <reserved0 value=\"0\"/>\n");
    out->writeText("    <reserved1 value=\"0\"/>\n");
    out->writeText("    <reserved2 value=\"0\"/>\n");
    out->writeText("    <reserved3 value=\"0\"/>\n");
    out->writeText("    <metricDataFormat value=\"0\"/>\n");
    out->writeText("    <numberOfHMetrics value=\"0\"/>\n");
    out->writeText("  </hhea>\n");

    // Some of this table is going to be re-calculated, but we have to write it out anyway.
    out->writeText("  <maxp>\n");
    out->writeText("    <tableVersion value=\"0x10000\"/>\n");
    out->writeText("    <numGlyphs value=\"");
    out->writeDecAsText(totalGlyphs);
    out->writeText("\"/>\n");
    out->writeText("    <maxPoints value=\"4\"/>\n");
    out->writeText("    <maxContours value=\"1\"/>\n");
    out->writeText("    <maxCompositePoints value=\"0\"/>\n");
    out->writeText("    <maxCompositeContours value=\"0\"/>\n");
    out->writeText("    <maxZones value=\"1\"/>\n");
    out->writeText("    <maxTwilightPoints value=\"0\"/>\n");
    out->writeText("    <maxStorage value=\"0\"/>\n");
    out->writeText("    <maxFunctionDefs value=\"10\"/>\n");
    out->writeText("    <maxInstructionDefs value=\"0\"/>\n");
    out->writeText("    <maxStackElements value=\"512\"/>\n");
    out->writeText("    <maxSizeOfInstructions value=\"24\"/>\n");
    out->writeText("    <maxComponentElements value=\"0\"/>\n");
    out->writeText("    <maxComponentDepth value=\"0\"/>\n");
    out->writeText("  </maxp>\n");

    out->writeText("  <OS_2>\n");
    out->writeText("    <version value=\"4\"/>\n");
    out->writeText("    <xAvgCharWidth value=\"");
    out->writeScalarAsText(fFontMetrics.fAvgCharWidth);
    out->writeText("\"/>\n");
    out->writeText("    <usWeightClass value=\"");
    out->writeDecAsText(this->fontStyle().weight());
    out->writeText("\"/>\n");
    out->writeText("    <usWidthClass value=\"");
    out->writeDecAsText(this->fontStyle().width());
    out->writeText("\"/>\n");
    out->writeText("    <fsType value=\"00000000 00000000\"/>\n");
    out->writeText("    <ySubscriptXSize value=\"665\"/>\n");
    out->writeText("    <ySubscriptYSize value=\"716\"/>\n");
    out->writeText("    <ySubscriptXOffset value=\"0\"/>\n");
    out->writeText("    <ySubscriptYOffset value=\"143\"/>\n");
    out->writeText("    <ySuperscriptXSize value=\"665\"/>\n");
    out->writeText("    <ySuperscriptYSize value=\"716\"/>\n");
    out->writeText("    <ySuperscriptXOffset value=\"0\"/>\n");
    out->writeText("    <ySuperscriptYOffset value=\"491\"/>\n");
    out->writeText("    <yStrikeoutSize value=\"");
    out->writeScalarAsText(fFontMetrics.fStrikeoutThickness);
    out->writeText("\"/>\n");
    out->writeText("    <yStrikeoutPosition value=\"");
    out->writeScalarAsText(-fFontMetrics.fStrikeoutPosition);
    out->writeText("\"/>\n");
    out->writeText("    <sFamilyClass value=\"0\"/>\n");
    out->writeText("    <panose>\n");
    out->writeText("      <bFamilyType value=\"0\"/>\n");
    out->writeText("      <bSerifStyle value=\"0\"/>\n");
    out->writeText("      <bWeight value=\"0\"/>\n");
    out->writeText("      <bProportion value=\"0\"/>\n");
    out->writeText("      <bContrast value=\"0\"/>\n");
    out->writeText("      <bStrokeVariation value=\"0\"/>\n");
    out->writeText("      <bArmStyle value=\"0\"/>\n");
    out->writeText("      <bLetterForm value=\"0\"/>\n");
    out->writeText("      <bMidline value=\"0\"/>\n");
    out->writeText("      <bXHeight value=\"0\"/>\n");
    out->writeText("    </panose>\n");
    out->writeText("    <ulUnicodeRange1 value=\"00000000 00000000 00000000 00000001\"/>\n");
    out->writeText("    <ulUnicodeRange2 value=\"00010000 00000000 00000000 00000000\"/>\n");
    out->writeText("    <ulUnicodeRange3 value=\"00000000 00000000 00000000 00000000\"/>\n");
    out->writeText("    <ulUnicodeRange4 value=\"00000000 00000000 00000000 00000000\"/>\n");
    out->writeText("    <achVendID value=\"Skia\"/>\n");
    char fsSelection[16] = {
            '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
    fsSelection[0xF - 0x7] = '1';  // Use typo metrics
    if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) {
        fsSelection[0xF - 0x5] = '1';  // Bold
    }
    switch (this->fontStyle().slant()) {
        case SkFontStyle::kUpright_Slant:
            if (this->fontStyle().weight() < SkFontStyle::Bold().weight()) {
                fsSelection[0xF - 0x6] = '1';  // Not bold or italic, is regular
            }
            break;
        case SkFontStyle::kItalic_Slant:
            fsSelection[0xF - 0x0] = '1';  // Italic
            break;
        case SkFontStyle::kOblique_Slant:
            fsSelection[0xF - 0x0] = '1';  // Italic
            fsSelection[0xF - 0x9] = '1';  // Oblique
            break;
        default: SK_ABORT("Unknown slant.");
    }
    out->writeText("    <fsSelection value=\"");
    out->write(fsSelection, 8);
    out->writeText(" ");
    out->write(fsSelection + 8, 8);
    out->writeText("\"/>\n");
    out->writeText("    <usFirstCharIndex value=\"0\"/>\n");
    out->writeText("    <usLastCharIndex value=\"0\"/>\n");
    out->writeText("    <sTypoAscender value=\"");
    out->writeScalarAsText(-fFontMetrics.fAscent);
    out->writeText("\"/>\n");
    out->writeText("    <sTypoDescender value=\"");
    out->writeScalarAsText(-fFontMetrics.fDescent);
    out->writeText("\"/>\n");
    out->writeText("    <sTypoLineGap value=\"");
    out->writeScalarAsText(fFontMetrics.fLeading);
    out->writeText("\"/>\n");
    out->writeText("    <usWinAscent value=\"");
    out->writeScalarAsText(-fFontMetrics.fAscent);
    out->writeText("\"/>\n");
    out->writeText("    <usWinDescent value=\"");
    out->writeScalarAsText(fFontMetrics.fDescent);
    out->writeText("\"/>\n");
    out->writeText("    <ulCodePageRange1 value=\"00000000 00000000 00000000 00000000\"/>\n");
    out->writeText("    <ulCodePageRange2 value=\"00000000 00000000 00000000 00000000\"/>\n");
    out->writeText("    <sxHeight value=\"");
    out->writeScalarAsText(fFontMetrics.fXHeight);
    out->writeText("\"/>\n");
    out->writeText("    <sCapHeight value=\"");
    out->writeScalarAsText(fFontMetrics.fCapHeight);
    out->writeText("\"/>\n");
    out->writeText("    <usDefaultChar value=\"0\"/>\n");
    out->writeText("    <usBreakChar value=\"32\"/>\n");
    out->writeText("    <usMaxContext value=\"0\"/>\n");
    out->writeText("  </OS_2>\n");

    out->writeText("  <hmtx>\n");
    for (int i = 0; i < fGlyphCount; ++i) {
        out->writeText("    <mtx name=\"glyf");
        out->writeHexAsText(i, 4);
        out->writeText("\" width=\"");
        out->writeDecAsText(fGlyphs[i].fAdvance);
        out->writeText("\" lsb=\"");
        int lsb = fGlyphs[i].fOrigin.fX;
        if (glyfInfo) {
            lsb += (*glyfInfo)[i].fBounds.fLeft;
        }
        out->writeDecAsText(lsb);
        out->writeText("\"/>\n");
    }
    if (glyfInfo) {
        for (int i = 0; i < fGlyphCount; ++i) {
            for (int j = 0; j < (*glyfInfo)[i].fLayers.size(); ++j) {
                out->writeText("    <mtx name=\"glyf");
                out->writeHexAsText(i, 4);
                out->writeText("l");
                out->writeHexAsText(j, 4);
                out->writeText("\" width=\"");
                out->writeDecAsText(fGlyphs[i].fAdvance);
                out->writeText("\" lsb=\"");
                int32_t lsb = fGlyphs[i].fOrigin.fX + (*glyfInfo)[i].fLayers[j].fBounds.fLeft;
                out->writeDecAsText(lsb);
                out->writeText("\"/>\n");
            }
        }
    }
    out->writeText("  </hmtx>\n");

    bool hasNonBMP = false;
    out->writeText("  <cmap>\n");
    out->writeText("    <tableVersion version=\"0\"/>\n");
    out->writeText("    <cmap_format_4 platformID=\"3\" platEncID=\"1\" language=\"0\">\n");
    fCMap.foreach ([&out, &hasNonBMP](const SkUnichar& c, const SkGlyphID& g) {
        if (0xFFFF < c) {
            hasNonBMP = true;
            return;
        }
        out->writeText("      <map code=\"0x");
        out->writeHexAsText(c, 4);
        out->writeText("\" name=\"glyf");
        out->writeHexAsText(g, 4);
        out->writeText("\"/>\n");
    });
    out->writeText("    </cmap_format_4>\n");
    if (hasNonBMP) {
        out->writeText(
                "    <cmap_format_12 platformID=\"3\" platEncID=\"10\" format=\"12\" "
                "reserved=\"0\" length=\"1\" language=\"0\" nGroups=\"0\">\n");
        fCMap.foreach ([&out](const SkUnichar& c, const SkGlyphID& g) {
            out->writeText("      <map code=\"0x");
            out->writeHexAsText(c, 6);
            out->writeText("\" name=\"glyf");
            out->writeHexAsText(g, 4);
            out->writeText("\"/>\n");
        });
        out->writeText("    </cmap_format_12>\n");
    }
    out->writeText("  </cmap>\n");

    out->writeText("  <name>\n");
    out->writeText(
            "    <namerecord nameID=\"1\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
    out->writeText("      ");
    out->writeText(fName.c_str());
    out->writeText(" ");
    out->writeText(type);
    out->writeText("\n");
    out->writeText("    </namerecord>\n");
    out->writeText(
            "    <namerecord nameID=\"2\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
    out->writeText("      Regular\n");
    out->writeText("    </namerecord>\n");
        out->writeText(
            "    <namerecord nameID=\"6\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
    out->writeText("      ");
    out->writeText(fName.c_str());
    out->writeText("_");
    out->writeText(type);
    out->writeText("\n");
    out->writeText("    </namerecord>\n");
    out->writeText("  </name>\n");

    out->writeText("  <post>\n");
    out->writeText("    <formatType value=\"3.0\"/>\n");
    out->writeText("    <italicAngle value=\"0.0\"/>\n");
    out->writeText("    <underlinePosition value=\"");
    out->writeScalarAsText(fFontMetrics.fUnderlinePosition);
    out->writeText("\"/>\n");
    out->writeText("    <underlineThickness value=\"");
    out->writeScalarAsText(fFontMetrics.fUnderlineThickness);
    out->writeText("\"/>\n");
    out->writeText("    <isFixedPitch value=\"0\"/>\n");
    out->writeText("    <minMemType42 value=\"0\"/>\n");
    out->writeText("    <maxMemType42 value=\"0\"/>\n");
    out->writeText("    <minMemType1 value=\"0\"/>\n");
    out->writeText("    <maxMemType1 value=\"0\"/>\n");
    out->writeText("  </post>\n");
}