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

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

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
package com.adobe.xfa.text;

import com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.gfx.GFXGlyphOrientation;
import com.adobe.xfa.ut.UnitSpan;

/*
 * @exclude from published api.
 */

class LineHeight extends TextLegacy {
	private TextAttr mpoPrevAttr;			// to avoid redundant calcs
	private int moAscent;					// max ascent
	private int moDescent;					// max descent
	private int moLineGap;					// max line gap
	private int moSize;						// max font Size
	private int moTextHeight;				// max text height (ascent + descent)
	private int moOverride;					// line spacing override (if > 0)
	private int moBefore;					// space before line
	private int moAfter;					// space after line
	private int moFullHeight;				// line height with before and after added
	private int moLegacySpacing;			// 6.0 line spacing
	private boolean mbOverrideCancelled;
	private boolean mbHasBaselineShift;		// any baseline shift found
	private boolean mbBaselineShiftStarted;	// started accumulating baseline?

	LineHeight () {
	}

	LineHeight (int legacyLevel) {
		setLegacyLevel (legacyLevel);
	}

	final int ascent () {
		return moAscent;
	}

	final int descent () {
		return moDescent;
	}

	final int lineGap () {
		return moLineGap;
	}

	final int size () {
		return moSize;
	}

// The test offset is actually the baseline offset.  It is computed by
// moving up by the maximum descent from the bottom of the line spacing
// (which may have been overridden).
	final int textOffset (int eGlyphOrientation) {
		int oBottom;

		if (hasLegacyPositioning()) {
			if (moOverride == 0) {
				oBottom = spacing();
			} else if (moOverride > moTextHeight) {
				oBottom = moOverride;
			} else {
				oBottom = moTextHeight;
			}
			oBottom -= moDescent;
		} else {
			oBottom = moOverride - moLineGap;
			if (oBottom < moTextHeight) {
				oBottom = moTextHeight;
			}
			if (GFXGlyphOrientation.usesHorizontalGlyphs (eGlyphOrientation)) {
				oBottom -= moDescent;
			} else {
				oBottom = (oBottom + 1) / 2;
			}
		}
		return moBefore + oBottom;
	}

	final int spacing () {
// Return spacing override if there is one.
		return (moOverride > 0) ? moOverride : (hasLegacyPositioning() ? moLegacySpacing : (moTextHeight + moLineGap));
	}

	final int override () {
		return moOverride;
	}

	final int fullHeight () {
		return moFullHeight;
	}

	final int before () {
		return moBefore;
	}

	final void before (int oNewBefore) {
		moBefore = oNewBefore;
	}

	final int after () {
		return moAfter;
	}

	final void after (int oNewAfter) {
		moAfter = oNewAfter;
	}

	final boolean hasBaselineShift () {
		return mbHasBaselineShift;
	}

	final void accumulateAscent (int oNewAscent) {
		if (oNewAscent > moAscent) {
			moAscent = oNewAscent;
		}
	}

	final void accumulateAscent (UnitSpan oNewAscent) {
		accumulateAscent (Units.toInt (oNewAscent));
	}

	final void accumulateDescent (int oNewDescent) {
		if (oNewDescent > moDescent) {
			moDescent = oNewDescent;
		}
	}

	final void accumulateDescent (UnitSpan oNewDescent) {
		accumulateDescent (Units.toInt (oNewDescent));
	}

	final void accumulateLineGap (int oNewLineGap) {
		if (oNewLineGap > moLineGap) {
			moLineGap = oNewLineGap;
		}
	}

	final void accumulateLineGap (UnitSpan oNewLineGap) {
		accumulateLineGap (Units.toInt (oNewLineGap));
	}

	final void accumulateSize (int oNewSize) {
		if (oNewSize > moSize) {
			moSize = oNewSize;
		}
	}

	final void accumulateSize (UnitSpan oNewSize) {
		accumulateSize (Units.toInt (oNewSize));
	}

	final void accumulateOverride (int oNewOverride) {
		if (oNewOverride > moOverride) {
			moOverride = oNewOverride;
		}
	}

	final void accumulateOverride (UnitSpan oNewOverride) {
		accumulateOverride (Units.toInt (oNewOverride));
	}

	final void accumulateLegacySpacing (int oNewLegacySpacing) {
		if (oNewLegacySpacing > moLegacySpacing) {
			moLegacySpacing = oNewLegacySpacing;
		}
	}

	final void accumulateLegacySpacing (int oAscent, int oDescent, int oLineGap) {
		accumulateLegacySpacing (oAscent + oDescent + oLineGap);
	}

	final void accumulateAfter (int oNewAfter) {
		if (oNewAfter > moAfter) {
			moAfter = oNewAfter;
		}
	}

	final void accumulateAfter (UnitSpan oNewAfter) {
		accumulateAfter (Units.toInt (oNewAfter));
	}

	final void accumulate (TextAttr poAttr, int eGlyphOrientation, boolean bFirstLineInStream) {
		HeightInfo info = canProcessAttr (poAttr, true);
		if (info == null) {
			return;
		}

		if (GFXGlyphOrientation.usesHorizontalGlyphs (eGlyphOrientation)) {
			accumulateAscent (info.ascent);
			accumulateDescent (info.descent);
		} else {
			accumulateSize (info.size);
		}

		if (! hasLegacyPositioning()) {
			accumulateLineGap (info.lineGap);
		} else {
			accumulateLegacySpacing (info.ascent, info.descent, info.lineGap);
		}

		boolean bBaselineShift = (poAttr.baselineShiftEnable()) && (! poAttr.baselineShift().isNeutral());
		if (bBaselineShift) {
			mbHasBaselineShift = true;
		}

		if (poAttr.spacingEnable()) {
			boolean bAccumulateOverride = false;
			UnitSpan spacing = poAttr.spacing().getLength();

			if (! bFirstLineInStream) {
				bAccumulateOverride = true;
			} else {
				int oLineSize = info.size;
				if (! hasLegacyPositioning()) {
					oLineSize = oLineSize + info.lineGap;
				}
				if (spacing.lt (Units.toUnitSpan (oLineSize))) {
					bAccumulateOverride = true;
				}
			}
			if (bAccumulateOverride) {
				accumulateOverride (spacing);
			}
		}
	}

	final void accumulateBaselineShift (TextAttr poAttr) {
		if (! mbBaselineShiftStarted) {
			mpoPrevAttr = null;
			if (moSize <= 0) {
				moSize = moAscent + moDescent;
			}
			mbBaselineShiftStarted = true;
		}

		HeightInfo info = canProcessAttr (poAttr, false);
		if (info == null) {
			return;
		}

		if ((poAttr.baselineShiftEnable()) && (! poAttr.baselineShift().isNeutral())) {
			UnitSpan us = Units.toUnitSpan (info.size);
			us = poAttr.baselineShift().applyShift (us, us);
			int oNewBaseline = Units.toInt (us);
			int oShift = oNewBaseline - info.size; // +ve is down shift

			if (hasLegacyPositioning()) {
				if (oShift < 0) {
					accumulateLegacySpacing (info.ascent - oShift, info.descent, info.lineGap);
				} else {
					accumulateAfter (oShift);
				}
			} else {
				accumulateAscent (info.ascent - oShift);
				accumulateDescent (info.descent + oShift);
			}
		}
	}

	final void reconcile () {
		if ((moAscent <= 0) && (moDescent <= 0)) {
			moTextHeight = moSize;
		} else {
			moTextHeight = moAscent + moDescent;
		}

		if (hasLegacyPositioning() && (moLegacySpacing < moTextHeight)) {
			moLegacySpacing = moTextHeight;
		}

		if (mbOverrideCancelled) {
			moOverride = 0;
		}

		moFullHeight = moBefore + spacing() + moAfter;
	}

	final boolean adjustLineSpacing (UnitSpan oTop) {
		if ((hasLegacyPositioning()) || (moOverride > 0) || (oTop.value() >= 0)) { // legacy positioning; must not adjust // forced line spacing; cannot adjust
			return false; // -ve value signals overflow above
		}

		int oDelta = Units.toInt (oTop);
		moAscent -= oDelta;
		moTextHeight -= oDelta;
		moFullHeight -= oDelta;

		return true;
	}

	final void reset () {
		moAscent = 0;
		moDescent = 0;
		moLineGap = 0;
		moTextHeight = 0;
		moSize = 0;
		moOverride = 0;
		moBefore = 0;
		moAfter = 0;
		moLegacySpacing = 0;
		mbOverrideCancelled = false;
		mbHasBaselineShift = false;
		mbBaselineShiftStarted = false;
		detach();
	}

	final void cancelOverride () {
		mbOverrideCancelled = true;
	}

	final void detach () {
		mpoPrevAttr = null; // don't carry dangling reference in case reused
	}

	private HeightInfo canProcessAttr (TextAttr poAttr, boolean bAccumulateSize) {
		if ((poAttr == null) || (poAttr == mpoPrevAttr)) {
			return null;
		}

		mpoPrevAttr = poAttr;

		FontInstance poFontInstance = poAttr.fontInstance();

		if (poFontInstance == null) {
			return null;
		}

		int ascent, descent, lineGap, size;

		if (hasLegacyPositioning()) {
			ascent = Units.toInt (poFontInstance.getLegacyAscent());
			descent = Units.toInt (poFontInstance.getSize()) - ascent;
			lineGap = Units.toInt (poFontInstance.getLegacyLineGap());
		} else {
			ascent = Units.toInt (poFontInstance.getAscent());
			descent = Units.toInt (poFontInstance.getDescent());
			lineGap = Units.toInt (poFontInstance.getLineGap());
		}

		if (poAttr.sizeEnable()) {
			size = Units.toInt (poAttr.size());
			if (bAccumulateSize) {
				accumulateSize (poAttr.size()); // if being called for full accumulation
			}
		} else {
			size = ascent + descent;
		}

		return new HeightInfo(ascent, descent, size, lineGap);
	}

	private static class HeightInfo {
		final int ascent;
		final int descent;
		final int size;
		final int lineGap;
		
		public HeightInfo(int ascent, int descent, int size, int lineGap) {
			this.ascent = ascent;
			this.descent = descent;
			this.size = size;
			this.lineGap = lineGap;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy