LayoutDriver.java 12.1 KB
/*
 * Decompiled with CFR 0_118.
 */
package com.adobe.xfa.text;

import com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.gfx.GFXDriver;
import com.adobe.xfa.gfx.GFXEnv;
import com.adobe.xfa.gfx.GFXMapping;
import com.adobe.xfa.gfx.GFXMappingList;
import com.adobe.xfa.text.DispLineWrapped;
import com.adobe.xfa.text.LayoutRenderer;
import com.adobe.xfa.text.MultiMapper;
import com.adobe.xfa.text.TextAttr;
import com.adobe.xfa.text.TextBaselineShift;
import com.adobe.xfa.text.TextFrame;
import com.adobe.xfa.text.TextGlyphRun;
import com.adobe.xfa.text.TextLayout;
import com.adobe.xfa.text.TextLayoutLine;
import com.adobe.xfa.text.TextSparseStream;
import com.adobe.xfa.text.Units;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.Rect;
import com.adobe.xfa.ut.UniCharIterator;
import com.adobe.xfa.ut.UnitSpan;

class LayoutDriver
extends GFXDriver {
    private final TextLayout mpoLayout;
    private final DispLineWrapped mpoDispLine;
    private final boolean mbAllowCharGlyphs;
    private final TextLayoutLine moLayoutLine = new TextLayoutLine();
    private final GFXMappingList moMappings = new GFXMappingList();
    private TextAttr mpoTextAttr;
    private final RunInfo mRunInfo;
    private final MultiMapper moMultiple = new MultiMapper();

    LayoutDriver(LayoutRenderer oRenderer, TextLayout poLayout, DispLineWrapped poDispLine, UnitSpan oFullAscent, UnitSpan oFullDescent, boolean bAllowCharGlyphs) {
        int eEndState;
        super(oRenderer);
        this.mpoLayout = poLayout;
        this.mpoDispLine = poDispLine;
        this.mbAllowCharGlyphs = bAllowCharGlyphs;
        this.mpoTextAttr = null;
        this.mRunInfo = new RunInfo(poDispLine.getXYOrigin().y().add(oFullAscent));
        this.initDeviceUnitsPerInch(1000, 1000);
        this.moLayoutLine.setFullAscent(oFullAscent);
        this.moLayoutLine.setFullDescent(oFullDescent);
        TextFrame poFrame = poDispLine.frame();
        TextSparseStream poStream = poFrame.getStream();
        int nIndex = poLayout.getLineCount();
        int eStartState = nIndex == 0 && poFrame == poStream.getFrame(0) ? 6 : (poDispLine.isFirstParaLine() ? 5 : 0);
        eStartState = LayoutDriver.ResolveLineEndState(eStartState, poDispLine.getStartBreak());
        this.moLayoutLine.setLineStartState(eStartState);
        if (nIndex + 1 == poFrame.getLineCount() && poFrame == poStream.getFrame(poStream.getFrameCount() - 1)) {
            eEndState = 6;
        } else {
            switch (poDispLine.getLastParaLine()) {
                case 2: {
                    eEndState = 4;
                    break;
                }
                case 3: {
                    eEndState = 5;
                    break;
                }
                default: {
                    eEndState = 0;
                }
            }
        }
        eEndState = LayoutDriver.ResolveLineEndState(eEndState, poDispLine.getEndBreak());
        this.moLayoutLine.setLineEndState(eEndState);
    }

    void finish() {
        this.flushMultiple();
        this.moLayoutLine.setMappings(this.moMappings);
        this.mpoLayout.addLine(this.moLayoutLine);
    }

    @Override
    public void absLine(CoordPair oEnd, int eDrawMode) {
    }

    @Override
    public void absFillRect(Rect oRect, int eDrawMode) {
    }

    @Override
    public void paraHint() {
    }

    @Override
    public void absText(String sText, int eDrawMode) {
        if (sText.length() == 0) {
            return;
        }
        if (this.mbAllowCharGlyphs) {
            CharRunHelper oHelper = new CharRunHelper(this.mpoTextAttr, sText);
            oHelper.generateRun(this.getAbsPosition(), this.moLayoutLine, this.mRunInfo);
        } else {
            CharGlyphRunHelper oHelper = new CharGlyphRunHelper(this.mpoTextAttr, sText);
            oHelper.generateRun(this.getAbsPosition(), this.moLayoutLine, this.mRunInfo);
        }
    }

    @Override
    public void absGlyphs(int[] pnGlyphs, int length) {
        if (length == 0) {
            return;
        }
        GlyphRunHelper oHelper = new GlyphRunHelper(this.mpoTextAttr, pnGlyphs, length);
        oHelper.generateRun(this.getAbsPosition(), this.moLayoutLine, this.mRunInfo);
        this.mRunInfo.mIsRTL = false;
    }

    @Override
    public void setUnicodeChars(int[] pcText) {
        StringBuilder sContent = new StringBuilder();
        int nSize = pcText.length;
        for (int i = 0; i < nSize; ++i) {
            int c = pcText[i];
            if (i + 1 == nSize) {
                switch (this.moLayoutLine.getLineEndState()) {
                    case 4: {
                        assert (c == 32);
                        c = 10;
                        break;
                    }
                    case 5: {
                        assert (c == 32);
                        c = 8233;
                    }
                }
            }
            sContent.append((char)c);
        }
        this.moLayoutLine.setContent(sContent.toString());
    }

    @Override
    public void mapGlyphs(GFXMappingList oMappings, boolean bIsRTL) {
        boolean bCharIndexFound = false;
        for (int i = 0; i < oMappings.getMappingCount(); ++i) {
            int eMultiple;
            int j;
            GFXMapping oRelMapping = oMappings.getMapping(i);
            if (!bCharIndexFound && oRelMapping.getCharCount() > 0) {
                int nCharIndex = oRelMapping.getCharIndex(0);
                TextAttr poAttr = this.mpoDispLine.getMappedAttr(nCharIndex);
                if (poAttr != null) {
                    this.mpoTextAttr = poAttr;
                }
                bCharIndexFound = true;
            }
            if ((eMultiple = this.moMultiple.canAccumulate(oRelMapping, this.mRunInfo.mGlyphCount)) != 2) {
                if (eMultiple == 1) {
                    this.flushMultiple();
                }
                this.moMultiple.accumulate(oRelMapping, this.mRunInfo.mGlyphCount);
                continue;
            }
            this.flushMultiple();
            GFXMapping oAbsMapping = new GFXMapping();
            for (j = 0; j < oRelMapping.getCharCount(); ++j) {
                oAbsMapping.addCharIndex(oRelMapping.getCharIndex(j));
            }
            for (j = 0; j < oRelMapping.getGlyphCount(); ++j) {
                oAbsMapping.addGlyphIndex(oRelMapping.getGlyphIndex(j) + this.mRunInfo.mGlyphCount);
            }
            this.moMappings.addMapping(oAbsMapping);
        }
        this.mRunInfo.mIsRTL = bIsRTL;
    }

    @Override
    public int getMappingLevel() {
        return 1;
    }

    @Override
    public int height() {
        return 65536;
    }

    @Override
    public int width() {
        return 65536;
    }

    @Override
    public boolean interactive() {
        return false;
    }

    @Override
    public void setClipRect(Rect oRect) {
    }

    private void flushMultiple() {
        this.moMultiple.flush(this.moMappings);
    }

    private static int ResolveLineEndState(int eLineState, int eBreakState) {
        if (eLineState == 0) {
            switch (eBreakState) {
                case 1: {
                    return 2;
                }
                case 2: {
                    return 1;
                }
                case 3: {
                    return 3;
                }
            }
        }
        return eLineState;
    }

    private static class GlyphRunHelper
    extends RunHelper {
        private final int[] mpnGlyphIDs;
        private final int mnLength;
        private int mnIndex;

        GlyphRunHelper(TextAttr poAttr, int[] pnGlyphIDs, int nLength) {
            super(poAttr, false);
            this.mpnGlyphIDs = pnGlyphIDs;
            this.mnLength = nLength;
            this.mnIndex = 0;
        }

        @Override
        protected RunHelper.GlyphInfo getNextGlyph() {
            if (this.mnIndex >= this.mnLength) {
                return null;
            }
            int nGlyph = this.mpnGlyphIDs[this.mnIndex];
            ++this.mnIndex;
            float oWidth = 0.0f;
            if (this.getFontInstance() != null) {
                oWidth = this.getFontInstance().getGlyphWidth(nGlyph, true);
            }
            return new RunHelper.GlyphInfo(nGlyph, oWidth);
        }
    }

    private static class CharGlyphRunHelper
    extends CharRunHelper {
        CharGlyphRunHelper(TextAttr poAttr, String sText) {
            super(poAttr, sText, false);
        }

        @Override
        protected RunHelper.GlyphInfo getNextGlyph() {
            int nGlyphID;
            RunHelper.GlyphInfo info = super.getNextGlyph();
            if (info == null) {
                return null;
            }
            if (this.getFontInstance() != null && (nGlyphID = this.getFontInstance().getGlyphID(info.mGlyphID)) != 0) {
                info = new RunHelper.GlyphInfo(nGlyphID, info.mGlyphWidth);
            }
            return info;
        }
    }

    private static class CharRunHelper
    extends RunHelper {
        private final UniCharIterator mIterator;

        CharRunHelper(TextAttr poAttr, String sText, boolean bCharMode) {
            super(poAttr, bCharMode);
            this.mIterator = new UniCharIterator(sText);
        }

        CharRunHelper(TextAttr poAttr, String sText) {
            this(poAttr, sText, true);
        }

        @Override
        protected RunHelper.GlyphInfo getNextGlyph() {
            int c = this.mIterator.next();
            if (c == 0) {
                return null;
            }
            float oWidth = this.getFontInstance() == null ? 0.0f : this.getFontInstance().getCharWidth(c, true);
            return new RunHelper.GlyphInfo(c, oWidth);
        }
    }

    private static abstract class RunHelper {
        private final TextAttr mpoAttr;
        private final boolean mbCharMode;
        private final FontInstance moFontInstance;

        void generateRun(CoordPair oPenPosn, TextLayoutLine oLayoutLine, RunInfo runInfo) {
            TextGlyphRun oRun = new TextGlyphRun();
            UnitSpan oVerticalShiftOffset = UnitSpan.ZERO;
            if (this.mpoAttr != null) {
                TextAttr poAttr = this.mpoAttr.getOriginalAttr();
                if (poAttr == null) {
                    poAttr = this.mpoAttr;
                } else {
                    oVerticalShiftOffset = this.mpoAttr.baselineShift().getLength();
                }
                oRun.setAttr(poAttr);
            }
            oRun.setCharRun(this.mbCharMode);
            oRun.setRTL(runInfo.mIsRTL);
            int nGlyphCount = 0;
            float oAccumulatedWidth = 0.0f;
            GlyphInfo glyphInfo = this.getNextGlyph();
            while (glyphInfo != null) {
                oRun.addGlyph(glyphInfo.mGlyphID);
                oAccumulatedWidth += glyphInfo.mGlyphWidth;
                glyphInfo = this.getNextGlyph();
                ++nGlyphCount;
            }
            CoordPair oRunPosn = new CoordPair(oPenPosn.x(), oPenPosn.y().subtract(oVerticalShiftOffset));
            oRun.setPosition(oRunPosn);
            if (!oRunPosn.equals(runInfo.mDefaultOffset)) {
                oRun.setShift(oRunPosn.subtract(runInfo.mDefaultOffset));
            }
            runInfo.mDefaultOffset = new CoordPair(oRunPosn.x().add(Units.toUnitSpan(oAccumulatedWidth)), runInfo.mDefaultOffset.y());
            oLayoutLine.addRun(oRun);
            runInfo.mGlyphCount += nGlyphCount;
        }

        protected RunHelper(TextAttr poAttr, boolean bCharMode) {
            this.mpoAttr = poAttr;
            this.mbCharMode = bCharMode;
            this.moFontInstance = poAttr != null ? poAttr.fontInstance() : null;
        }

        protected FontInstance getFontInstance() {
            return this.moFontInstance;
        }

        protected abstract GlyphInfo getNextGlyph();

        static class GlyphInfo {
            final int mGlyphID;
            final float mGlyphWidth;

            GlyphInfo(int glyphID, float glyphWidth) {
                this.mGlyphID = glyphID;
                this.mGlyphWidth = glyphWidth;
            }
        }

    }

    static class RunInfo {
        int mGlyphCount = 0;
        CoordPair mDefaultOffset;
        boolean mIsRTL;

        RunInfo(UnitSpan initialY) {
            this.mDefaultOffset = new CoordPair(UnitSpan.ZERO, initialY);
            this.mIsRTL = false;
        }
    }

}