All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.text.DrawRun Maven / Gradle / Ivy

There is a newer version: 2024.11.18598.20241113T125352Z-241000
Show newest version
package com.adobe.xfa.text;

import com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.gfx.GFXDriver;
import com.adobe.xfa.gfx.GFXMappingList;
import com.adobe.xfa.ut.CoordPair;
import com.adobe.xfa.ut.UniCharIterator;

/**
 * @exclude from published api.
 */

class DrawRun {
	private final DispLineWrapped mpoLine;	// owning displey line
	private final DrawParm moParm;			// draw parameters

	private final DrawAttr moAttr;			// run attributes
	private boolean mbAttrChange;			// is there an attribute change before this run?

	private final DrawAttr.ClipRect moClipRect;	// clip rectangle

	private final StringBuilder msChar = new StringBuilder();	// character data run
	private int mnRunStart; 				// start of run in line's character data
	private int mnRunLength;				// length of run in line's character data
	private int mnGlyphCount;				// number of accumulated glyphs
	private boolean mbGlyphMode;			// is this run in glyph mode?
	private boolean mbIsRTL;				// are these RTL glyphs?

	private final GFXMappingList moMappingList;	// accumulated mappings for this run
	private final int meMappingType;			// type of mapping required by driver

	private float moX;						// run start position X
	private float moY;						// run start position Y
	private float moPrevX;					// previous position X
	private float moPrevY;					// previous position Y
	private boolean mbUnknownWidth; 		// last glyph has unknown width?

	private float moCharSpacing;					// current char spacing
	private final boolean mbCharSpacingSupported;	// driver supports char spacing?
	private float moWordSpacing;					// current word spacing
	private final boolean mbWordSpacingSupported;	// driver supports word spacing?

	private final MultiMapper moMultiple = new MultiMapper();	// for mapping 1 char to multiple glyphs

	DrawRun (DispLineWrapped poLine, DrawParm oParm) {
		mpoLine = poLine;
		moParm = oParm;
		moAttr = new DrawAttr (poLine, oParm);
		mbAttrChange = true;				// force out first attr encountered
		moClipRect = new DrawAttr.ClipRect (oParm);
//		mnRunStart = 0;
//		mnRunLength = 0;
//		mnGlyphCount = 0;
//		mbGlyphMode = false;
//		mbIsRTL = false;
		moMappingList = poLine.display().getContext().getMappingList();
		meMappingType = oParm.driver().getMappingLevel();
//		mbUnknownWidth = false;
		mbCharSpacingSupported = oParm.driver().charSpacingSupported();
		mbWordSpacingSupported = oParm.driver().wordSpacingSupported();
		if (meMappingType == GFXDriver.MAPPING_FULL) {
			moMappingList.reset();
		}
	}

	void addGlyph (DrawAttr oCurrentAttr,
					RenderInfo oRenderInfo,
					float oX,
					float oY,
					boolean bIsRTL) {
		boolean bNewGlyphMode = oRenderInfo.mcGlyph == '\0';

		if (bNewGlyphMode != mbGlyphMode) {
			flush();
			mbGlyphMode = bNewGlyphMode;
		}

		setupRun (oCurrentAttr, oRenderInfo, oX, oY, bIsRTL);

		int nRunStart = oRenderInfo.mpoGlyphLoc.getMapIndex();
		int nRunLength = oRenderInfo.mpoGlyphLoc.getMapLength();

		if (mpoLine.hasAXTEMappings())
		{
			int nAdjustedRunStart = nRunStart;
			int nPosnIndex = 0;
			DispPosn poPosition = null;

			for (; nPosnIndex < mpoLine.getPositionCount(); nPosnIndex++) {
				DispPosn oPosition = mpoLine.getPosition (nPosnIndex);
				if (oPosition.getMapIndex() + oPosition.getMapLength() > nRunStart) {
					poPosition = oPosition;
					break;
				}
				nAdjustedRunStart += DispLine.getPositionStreamCount (oPosition);
				nAdjustedRunStart -= oPosition.getMapLength();
			}
			assert (poPosition != null);

			nRunStart = nAdjustedRunStart;
			switch (DispLine.getPositionType (poPosition)) {
				case DispLine.POSN_TYPE_LIGATURE:
					assert (poPosition.getMapLength() == 1);
					nRunLength = DispLine.getPositionStreamCount (poPosition);
					break;
				case DispLine.POSN_TYPE_MULTIPLE:
					nRunStart -= oRenderInfo.mpoGlyphLoc.getMapIndex() - poPosition.getMapIndex();
					nRunLength = 1;
					break;
			}
		}

		if (mbGlyphMode) {
			int[] oGlyphArray = mpoLine.display().getContext().getGlyphArray (mnGlyphCount + 1);
			oGlyphArray[mnGlyphCount] = oRenderInfo.mnGlyphID;

// Watson 1023477: Cannot simply add the number of characters covered by
// this glyph, because some characters create multiple glyphs causing the
// character to be double-counted.	Instead, compute the length from the
// character(s) covered by this glyph.	TBD: can remove this and collaps
// mnRunLength into mnGlyphCount once Acrobat stops using legacy mapping.
			if (mnRunLength == 0) {
				mnRunStart = nRunStart;
				mnRunLength = nRunLength;
			} else {
				int nGlyphStart = nRunStart;
				int nGlyphMax = nGlyphStart + nRunLength;
				int nRunMax = mnRunStart + mnRunLength;
				if (nGlyphStart < mnRunStart) {
					mnRunStart = nGlyphStart;
				}
				if (nGlyphMax > nRunMax) {
					nRunMax = nGlyphMax;
				}
				mnRunLength = nRunMax - mnRunStart;
			}

			accumulateMapping (nRunStart, mnGlyphCount, nRunLength);
			updatePosition (oRenderInfo.mpoGlyphLoc, oX, oY, oRenderInfo.mnGlyphID, true);
		}

		else {
			msChar.append ((char) oRenderInfo.mcGlyph);

			updatePosition (oRenderInfo.mpoGlyphLoc, oX, oY, oRenderInfo.mnGlyphID, false);
//			updatePosition (oRenderInfo.mpoGlyphLoc, oX, oY, oRenderInfo.mcGlyph, false);
			accumulateMapping (nRunStart, mnGlyphCount);

			mnRunLength++;
		}

		mnGlyphCount++;
	}

	void flush () {
		if (mnGlyphCount > 0) {
			StringBuilder debugMsg = null;
			TextContext context = mpoLine.display().getContext();
			if (context.debug()) {
				debugMsg = new StringBuilder();
			}

			if (mbGlyphMode) {
				int[] oGlyphArray = context.getGlyphArray();
				if (flushCommon (debugMsg)) {
					if (debugMsg != null) {
						debugMsg.append (" Glyphs:");
						for (int i = 0; i < mnGlyphCount; i++) {
							debugMsg.append (' ');
							debugMsg.append (Integer.toString (oGlyphArray[i]));
						}
						context.debug (debugMsg.toString());
					}
					moParm.driver().relGlyphs (oGlyphArray, mnGlyphCount);
				}
			}

			else {
				if (flushCommon (debugMsg)) {
					if (debugMsg != null) {
						debugMsg.append (" Chars:");
						UniCharIterator iter = new UniCharIterator (msChar);
						int c;
						for (c = iter.next(); c != 0; c = iter.next()) {
							debugMsg.append (' ');
							debugMsg.append (Integer.toString (c));
						}
						context.debug (debugMsg.toString());
					}
					moParm.driver().relText (msChar.toString());
				}
				msChar.delete (0, msChar.length());
			}

			mnRunLength = 0;
			mnGlyphCount = 0;
		}
	}

	void clear () {
		moClipRect.detach();
	}

	void forceAttrChange () {
		mbAttrChange = true;
	}

	private void setupRun (DrawAttr oCurrentAttr, RenderInfo oRenderInfo, float oX, float oY, boolean bIsRTL) {
		if ((mnGlyphCount > 0) && (! mbUnknownWidth) && (! mpoLine.legacyPositioning())) {
			if ((moAttr.getFontOverride() != null)
			 || ((moAttr.getAttr() != null) && (moAttr.getAttr().fontInstance() != null))) {
				if ((oX != moPrevX) || (oY != moPrevY)) {
					if ((Math.abs (oX - moPrevX) > 0.001) || (Math.abs (oY - moPrevY) > 0.001)) {
						flush();
					}
				}
			}
		}

		if (mnGlyphCount == 0) {
			moAttr.reset (oCurrentAttr);
			mnRunStart = oRenderInfo.mpoGlyphLoc.getMapIndex();
			moX = oX;
			moY = oY;
			mbIsRTL = bIsRTL;

			moCharSpacing = 0;
			moWordSpacing = 0;
			TextAttr poAttr = moAttr.getAttr();
			if (poAttr != null) {
				if (poAttr.charSpacingEnable()) {
					moCharSpacing = Units.toFloat (poAttr.charSpacing().getLength());
				}
				if (poAttr.wordSpacingEnable()) {
					moWordSpacing = Units.toFloat (poAttr.wordSpacing().getLength());
				}
			}

			if (oRenderInfo.mbAttrChange) {
				mbAttrChange = true;
				oRenderInfo.mbAttrChange = false;
			}
		}
	}

	private boolean flushCommon (StringBuilder debugMsg) {
		boolean attrChange = mbAttrChange;
		mbAttrChange = false;
		if (attrChange && (! moAttr.assertAttrs (moClipRect))) {
			return false;
		}

		GFXDriver poDriver = moParm.driver();

		CoordPair oOffset = new CoordPair (Units.toUnitSpan (moX), Units.toUnitSpan (moY));
		oOffset = ABXY.toXY (mpoLine.getXYOrigin(), oOffset, mpoLine.frame().getLayoutOrientation());
		poDriver.relPosition (oOffset);
		if (debugMsg != null) {
			debugMsg.append ("At Y=");
			debugMsg.append (oOffset.y().toString());
			debugMsg.append (", X=");
			debugMsg.append (oOffset.x().toString());
			debugMsg.append (", ");
		}

		flushMultiple();

		switch (meMappingType)
		{
			case GFXDriver.MAPPING_LEGACY:
				poDriver.mapChars (mnRunStart, mnRunLength);
				break;
			case GFXDriver.MAPPING_FULL:
				poDriver.mapGlyphs (moMappingList, mbIsRTL);
				moMappingList.reset();
				break;
		}

		return true;
	}

	private void updatePosition (GlyphLoc poGlyphLoc, float oX, float oY, int nGlyph, boolean bIsGlyph) {
		FontInstance oFontInstance = moAttr.getWorkingFont();

		mbUnknownWidth = true;
		moPrevX = oX;
		moPrevY = oY;

		if (oFontInstance != null) {
			boolean bHorizontal = ! mpoLine.verticalOrientation();
			float oOffset = oFontInstance.getGlyphWidth (nGlyph, bHorizontal);
//			float oOffset = bIsGlyph ? oFontInstance.getGlyphWidth (nGlyph, bHorizontal)
//					 : oFontInstance.getCharWidth (nGlyph, bHorizontal);

			if (oOffset >= 0) {
				mbUnknownWidth = false;

				if (mbCharSpacingSupported) {
					oOffset += moCharSpacing;
				}

				if (mbWordSpacingSupported && (mpoLine.getBreakClass (poGlyphLoc.getMapIndex()) == TextCharProp.BREAK_SP)) {
					oOffset += moWordSpacing;
				}

				moPrevX += oOffset;
			}
		}
	}

	private void accumulateMapping (int nCharIndex, int nGlyphIndex, int nCharLength) {
		if (meMappingType != GFXDriver.MAPPING_FULL) {
			return;
		}

		if (nCharLength != 1) {
			flushMultiple();
			moMappingList.addMapping (nCharIndex, nGlyphIndex, nCharLength);
			return;
		}

//		if (moMultiple == null) {
//			moMultiple = new MultiMapper();
//		}
		if (! moMultiple.canAccumulate (nCharIndex, nGlyphIndex)) {
			flushMultiple();
		}
		moMultiple.accumulate (nCharIndex, nGlyphIndex);
	}
	private void accumulateMapping (int nCharIndex, int nGlyphIndex) {
		accumulateMapping (nCharIndex, nGlyphIndex, 1);
	}

	private void flushMultiple () {
		moMultiple.flush (moMappingList);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy