You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AlignmentContext.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.layoutmgr.inline;
  19. import org.apache.fop.datatypes.Length;
  20. import org.apache.fop.datatypes.LengthBase;
  21. import org.apache.fop.datatypes.SimplePercentBaseContext;
  22. import org.apache.fop.fo.Constants;
  23. import org.apache.fop.fonts.Font;
  24. import org.apache.fop.traits.WritingMode;
  25. /**
  26. * The alignment context is carried within a LayoutContext and as
  27. * part of the Knuth Inline elements to facilitate proper line building.
  28. * All measurements are in mpt.
  29. */
  30. public class AlignmentContext implements Constants {
  31. /** The height or BPD of this context. */
  32. private int areaHeight;
  33. /** The computed line-height property value applicable. */
  34. private int lineHeight;
  35. /** The distance in BPD from the top of the box to the alignmentPoint. */
  36. private int alignmentPoint;
  37. /** The baseline shift value in effect. */
  38. private int baselineShiftValue;
  39. /** The computed alignment baseline identifier. */
  40. private int alignmentBaselineIdentifier;
  41. /** The x height. */
  42. private int xHeight;
  43. private ScaledBaselineTable scaledBaselineTable;
  44. private ScaledBaselineTable actualBaselineTable;
  45. private AlignmentContext parentAlignmentContext;
  46. /**
  47. * Creates a new instance of AlignmentContext
  48. * for graphics areas.
  49. * @param height the total height of the area
  50. * @param alignmentAdjust the alignment-adjust property
  51. * @param alignmentBaseline the alignment-baseline property
  52. * @param baselineShift the baseline-shift property
  53. * @param dominantBaseline the dominant-baseline property
  54. * @param parentAlignmentContext the parent alignment context
  55. */
  56. AlignmentContext(int height,
  57. Length alignmentAdjust,
  58. int alignmentBaseline,
  59. Length baselineShift,
  60. int dominantBaseline,
  61. AlignmentContext parentAlignmentContext) {
  62. this(height, 0, height, height, alignmentAdjust, alignmentBaseline, baselineShift,
  63. dominantBaseline, parentAlignmentContext);
  64. }
  65. /**
  66. * Creates a new instance.
  67. *
  68. * @param font the font
  69. * @param lineHeight the computed value of the lineHeight property
  70. * @param alignmentAdjust the alignment-adjust property
  71. * @param alignmentBaseline the alignment-baseline property
  72. * @param baselineShift the baseline-shift property
  73. * @param dominantBaseline the dominant-baseline property
  74. * @param parentAlignmentContext the parent alignment context
  75. */
  76. AlignmentContext(Font font,
  77. int lineHeight,
  78. Length alignmentAdjust,
  79. int alignmentBaseline,
  80. Length baselineShift,
  81. int dominantBaseline,
  82. AlignmentContext parentAlignmentContext) {
  83. this(font.getAscender(), font.getDescender(), lineHeight, font.getXHeight(),
  84. alignmentAdjust, alignmentBaseline, baselineShift, dominantBaseline,
  85. parentAlignmentContext);
  86. }
  87. /**
  88. * Creates a new instance of AlignmentContext.
  89. * @param altitude the altitude of the area
  90. * @param depth the depth of the area
  91. * @param lineHeight the line height
  92. * @param xHeight the xHeight
  93. * @param alignmentAdjust the alignment-adjust property
  94. * @param alignmentBaseline the alignment-baseline property
  95. * @param baselineShift the baseline-shift property
  96. * @param dominantBaseline the dominant-baseline property
  97. * @param parentAlignmentContext the parent alignment context
  98. */
  99. private AlignmentContext(int altitude,
  100. int depth,
  101. int lineHeight,
  102. int xHeight,
  103. Length alignmentAdjust,
  104. int alignmentBaseline,
  105. Length baselineShift,
  106. int dominantBaseline,
  107. AlignmentContext parentAlignmentContext) {
  108. this.areaHeight = altitude - depth;
  109. this.lineHeight = lineHeight;
  110. this.xHeight = xHeight;
  111. this.parentAlignmentContext = parentAlignmentContext;
  112. this.scaledBaselineTable = parentAlignmentContext.getScaledBaselineTable();
  113. setAlignmentBaselineIdentifier(alignmentBaseline
  114. , parentAlignmentContext.getDominantBaselineIdentifier());
  115. setBaselineShift(baselineShift);
  116. int dominantBaselineIdentifier = parentAlignmentContext.getDominantBaselineIdentifier();
  117. boolean newScaledBaselineTableRequired = false;
  118. if (baselineShiftValue != 0) {
  119. newScaledBaselineTableRequired = true;
  120. }
  121. switch (dominantBaseline) {
  122. case EN_AUTO:
  123. newScaledBaselineTableRequired = baselineShiftValue != 0;
  124. break;
  125. case EN_USE_SCRIPT: // TODO
  126. break;
  127. case EN_NO_CHANGE:
  128. break;
  129. case EN_RESET_SIZE:
  130. newScaledBaselineTableRequired = true;
  131. break;
  132. default:
  133. newScaledBaselineTableRequired = true;
  134. dominantBaselineIdentifier = dominantBaseline;
  135. break;
  136. }
  137. actualBaselineTable = new ScaledBaselineTable(
  138. altitude,
  139. depth,
  140. xHeight,
  141. dominantBaselineIdentifier,
  142. scaledBaselineTable.getWritingMode());
  143. if (newScaledBaselineTableRequired) {
  144. scaledBaselineTable = new ScaledBaselineTable(
  145. altitude,
  146. depth,
  147. xHeight,
  148. dominantBaselineIdentifier,
  149. scaledBaselineTable.getWritingMode());
  150. }
  151. setAlignmentAdjust(alignmentAdjust);
  152. }
  153. /**
  154. * Creates a new instance of AlignmentContext based simply
  155. * on the font and the writing mode.
  156. * @param font the font
  157. * @param lineHeight the computed value of the lineHeight property
  158. * @param writingMode the current writing mode
  159. */
  160. AlignmentContext(Font font, int lineHeight, WritingMode writingMode) {
  161. this.areaHeight = font.getAscender() - font.getDescender();
  162. this.lineHeight = lineHeight;
  163. this.xHeight = font.getXHeight();
  164. this.scaledBaselineTable = new ScaledBaselineTable(font.getAscender(), font.getDescender(),
  165. font.getXHeight(), Constants.EN_ALPHABETIC, writingMode);
  166. this.actualBaselineTable = scaledBaselineTable;
  167. this.alignmentBaselineIdentifier = getDominantBaselineIdentifier();
  168. this.alignmentPoint = font.getAscender();
  169. this.baselineShiftValue = 0;
  170. }
  171. /**
  172. * Returns the alignment point for this context.
  173. * This is the point on the start edge of the area this context
  174. * applies to measured from the before edge of the area.
  175. * @return the default alignment point
  176. */
  177. public int getAlignmentPoint() {
  178. return alignmentPoint;
  179. }
  180. /**
  181. * Returns the current value of baseline shift in effect.
  182. * @return the baseline shift
  183. */
  184. public int getBaselineShiftValue() {
  185. return baselineShiftValue;
  186. }
  187. /**
  188. * Returns the current alignment baseline identifier.
  189. *
  190. * @return the alignment baseline identifier
  191. */
  192. public int getAlignmentBaselineIdentifier() {
  193. return alignmentBaselineIdentifier;
  194. }
  195. /**
  196. * Sets the current alignment baseline identifier. For
  197. * alignment-baseline values of "auto" and "baseline" this
  198. * method does the conversion into the appropriate computed
  199. * value assuming script is "auto" and the fo is not fo:character.
  200. * @param alignmentBaseline the alignment-baseline property
  201. * @param parentDominantBaselineIdentifier the dominant baseline of the parent fo
  202. */
  203. private void setAlignmentBaselineIdentifier(int alignmentBaseline
  204. , int parentDominantBaselineIdentifier) {
  205. switch (alignmentBaseline) {
  206. case EN_AUTO: // fall through
  207. case EN_BASELINE:
  208. this.alignmentBaselineIdentifier = parentDominantBaselineIdentifier;
  209. break;
  210. case EN_BEFORE_EDGE:
  211. case EN_TEXT_BEFORE_EDGE:
  212. case EN_CENTRAL:
  213. case EN_MIDDLE:
  214. case EN_AFTER_EDGE:
  215. case EN_TEXT_AFTER_EDGE:
  216. case EN_IDEOGRAPHIC:
  217. case EN_ALPHABETIC:
  218. case EN_HANGING:
  219. case EN_MATHEMATICAL:
  220. this.alignmentBaselineIdentifier = alignmentBaseline;
  221. break;
  222. default: throw new IllegalArgumentException(String.valueOf(alignmentBaseline));
  223. }
  224. }
  225. /**
  226. * Sets the current alignment baseline identifer. For
  227. * alignment-baseline values of "auto" and "baseline" this
  228. * method does the conversion into the appropriate computed
  229. * value assuming script is "auto" and the fo is not fo:character.
  230. * @param alignmentAdjust the alignment-adjust property
  231. */
  232. private void setAlignmentAdjust(Length alignmentAdjust) {
  233. int beforeEdge = actualBaselineTable.getBaseline(EN_BEFORE_EDGE);
  234. switch (alignmentAdjust.getEnum()) {
  235. case EN_AUTO:
  236. alignmentPoint = beforeEdge
  237. - actualBaselineTable.getBaseline(alignmentBaselineIdentifier);
  238. break;
  239. case EN_BASELINE:
  240. alignmentPoint = beforeEdge;
  241. break;
  242. case EN_BEFORE_EDGE:
  243. case EN_TEXT_BEFORE_EDGE:
  244. case EN_CENTRAL:
  245. case EN_MIDDLE:
  246. case EN_AFTER_EDGE:
  247. case EN_TEXT_AFTER_EDGE:
  248. case EN_IDEOGRAPHIC:
  249. case EN_ALPHABETIC:
  250. case EN_HANGING:
  251. case EN_MATHEMATICAL:
  252. alignmentPoint = beforeEdge
  253. - actualBaselineTable.getBaseline(alignmentAdjust.getEnum());
  254. break;
  255. default:
  256. alignmentPoint = beforeEdge
  257. + alignmentAdjust.getValue(new SimplePercentBaseContext(null
  258. , LengthBase.ALIGNMENT_ADJUST
  259. , lineHeight));
  260. break;
  261. }
  262. }
  263. /**
  264. * Return the scaled baseline table for this context.
  265. * @return the scaled baseline table
  266. */
  267. private ScaledBaselineTable getScaledBaselineTable() {
  268. return this.scaledBaselineTable;
  269. }
  270. /**
  271. * Return the dominant baseline identifier.
  272. * @return the dominant baseline identifier
  273. */
  274. public int getDominantBaselineIdentifier() {
  275. return actualBaselineTable.getDominantBaselineIdentifier();
  276. }
  277. /**
  278. * Return the writing mode.
  279. * @return the writing mode
  280. */
  281. /* public WritingMode getWritingMode() {
  282. return scaledBaselineTable.getWritingMode();
  283. }*/
  284. /**
  285. * Calculates the baseline shift value based on the baseline-shift
  286. * property value.
  287. * @param baselineShift the baseline shift property value
  288. */
  289. private void setBaselineShift(Length baselineShift) {
  290. baselineShiftValue = 0;
  291. switch (baselineShift.getEnum()) {
  292. case EN_BASELINE: //Nothing to do
  293. break;
  294. case EN_SUB:
  295. baselineShiftValue = Math.round(-((float)xHeight / 2)
  296. + (float)parentAlignmentContext.getActualBaselineOffset(EN_ALPHABETIC)
  297. );
  298. break;
  299. case EN_SUPER:
  300. baselineShiftValue = Math.round((float)parentAlignmentContext.getXHeight()
  301. + (float)parentAlignmentContext.getActualBaselineOffset(EN_ALPHABETIC)
  302. );
  303. break;
  304. case 0: // A <length> or <percentage> value
  305. baselineShiftValue = baselineShift.getValue(
  306. new SimplePercentBaseContext(null
  307. , LengthBase.CUSTOM_BASE
  308. , parentAlignmentContext.getLineHeight()));
  309. break;
  310. default: throw new IllegalArgumentException(String.valueOf(baselineShift.getEnum()));
  311. }
  312. }
  313. /**
  314. * Return the parent alignment context.
  315. * @return the parent alignment context
  316. */
  317. public AlignmentContext getParentAlignmentContext() {
  318. return parentAlignmentContext;
  319. }
  320. /**
  321. * Return the offset between the current dominant baseline and
  322. * the parent dominant baseline.
  323. * @return the offset in shift direction
  324. */
  325. private int getBaselineOffset() {
  326. if (parentAlignmentContext == null) {
  327. return 0;
  328. }
  329. return parentAlignmentContext.getScaledBaselineTable()
  330. .getBaseline(alignmentBaselineIdentifier)
  331. - scaledBaselineTable
  332. .deriveScaledBaselineTable(parentAlignmentContext
  333. .getDominantBaselineIdentifier())
  334. .getBaseline(alignmentBaselineIdentifier)
  335. - scaledBaselineTable
  336. .getBaseline(parentAlignmentContext
  337. .getDominantBaselineIdentifier())
  338. + baselineShiftValue;
  339. }
  340. /**
  341. * Return the offset between the current dominant baseline and
  342. * the outermost parent dominant baseline.
  343. * @return the offset in shift direction
  344. */
  345. private int getTotalBaselineOffset() {
  346. int offset = 0;
  347. if (parentAlignmentContext != null) {
  348. offset = getBaselineOffset() + parentAlignmentContext.getTotalBaselineOffset();
  349. }
  350. return offset;
  351. }
  352. /**
  353. * Return the offset between the alignment baseline and
  354. * the outermost parent dominant baseline.
  355. * @return the offset in shift direction
  356. */
  357. public int getTotalAlignmentBaselineOffset() {
  358. return getTotalAlignmentBaselineOffset(alignmentBaselineIdentifier);
  359. }
  360. /**
  361. * Return the offset between the given alignment baseline and
  362. * the outermost parent dominant baseline.
  363. * @param alignmentBaselineId the alignment baseline
  364. * @return the offset
  365. */
  366. private int getTotalAlignmentBaselineOffset(int alignmentBaselineId) {
  367. int offset = baselineShiftValue;
  368. if (parentAlignmentContext != null) {
  369. offset = parentAlignmentContext.getTotalBaselineOffset()
  370. + parentAlignmentContext.getScaledBaselineTable()
  371. .getBaseline(alignmentBaselineId)
  372. + baselineShiftValue;
  373. }
  374. return offset;
  375. }
  376. /**
  377. * Return the offset between the dominant baseline and
  378. * the given actual baseline.
  379. *
  380. * @param baselineIdentifier the baseline
  381. * @return the offset
  382. */
  383. private int getActualBaselineOffset(int baselineIdentifier) {
  384. // This is the offset from the dominant baseline to the alignment baseline
  385. int offset = getTotalAlignmentBaselineOffset() - getTotalBaselineOffset();
  386. // Add the offset to the actual baseline we want
  387. offset += actualBaselineTable.deriveScaledBaselineTable(alignmentBaselineIdentifier)
  388. .getBaseline(baselineIdentifier);
  389. return offset;
  390. }
  391. /**
  392. * Return the offset the outermost parent dominant baseline
  393. * and the top of this box.
  394. * @return the offset
  395. */
  396. private int getTotalTopOffset() {
  397. int offset = getTotalAlignmentBaselineOffset() + getAltitude();
  398. return offset;
  399. }
  400. /**
  401. * Return the total height of the context.
  402. * @return the height
  403. */
  404. public int getHeight() {
  405. return areaHeight;
  406. }
  407. /**
  408. * Return the line height of the context.
  409. * @return the height
  410. */
  411. private int getLineHeight() {
  412. return lineHeight;
  413. }
  414. /**
  415. * The altitude of the context that is the height above the
  416. * alignment point.
  417. * @return the altitude
  418. */
  419. public int getAltitude() {
  420. return alignmentPoint;
  421. }
  422. /**
  423. * The depth of the context that is the height below
  424. * alignment point.
  425. * @return the altitude
  426. */
  427. public int getDepth() {
  428. return getHeight() - alignmentPoint;
  429. }
  430. /**
  431. * The x height of the context.
  432. * @return the x height
  433. */
  434. private int getXHeight() {
  435. return this.xHeight;
  436. }
  437. /**
  438. * Resizes the line as specified. Assumes that the new alignment point
  439. * is on the dominant baseline, that is this function should be called for
  440. * line areas only.
  441. * @param newLineHeight the new height of the line
  442. * @param newAlignmentPoint the new alignment point
  443. */
  444. public void resizeLine(int newLineHeight, int newAlignmentPoint) {
  445. areaHeight = newLineHeight;
  446. alignmentPoint = newAlignmentPoint;
  447. scaledBaselineTable.setBeforeAndAfterBaselines(alignmentPoint
  448. , alignmentPoint - areaHeight);
  449. }
  450. /**
  451. * Returns the offset from the before-edge of the parent to
  452. * this context.
  453. * @return the offset for rendering
  454. */
  455. public int getOffset() {
  456. int offset = 0;
  457. if (parentAlignmentContext != null) {
  458. offset = parentAlignmentContext.getTotalTopOffset() - getTotalTopOffset();
  459. } else {
  460. offset = getAltitude() - scaledBaselineTable.getBaseline(EN_TEXT_BEFORE_EDGE);
  461. }
  462. return offset;
  463. }
  464. /**
  465. * Returns an indication if we still use the initial baseline table.
  466. * The initial baseline table is the table generated by the Line LM.
  467. * @return true if this is still the initial baseline table
  468. */
  469. public boolean usesInitialBaselineTable() {
  470. return parentAlignmentContext == null
  471. || (scaledBaselineTable == parentAlignmentContext.getScaledBaselineTable()
  472. && parentAlignmentContext.usesInitialBaselineTable());
  473. }
  474. /* private boolean isHorizontalWritingMode() {
  475. return (getWritingMode() == WritingMode.LR_TB || getWritingMode() == WritingMode.RL_TB);
  476. }*/
  477. /** {@inheritDoc} */
  478. public String toString() {
  479. StringBuffer sb = new StringBuffer(64);
  480. sb.append("areaHeight=").append(areaHeight);
  481. sb.append(" lineHeight=").append(lineHeight);
  482. sb.append(" alignmentPoint=").append(alignmentPoint);
  483. sb.append(" alignmentBaselineID=").append(alignmentBaselineIdentifier);
  484. sb.append(" baselineShift=").append(baselineShiftValue);
  485. return sb.toString();
  486. }
  487. }