/* ScriptsAtom.java
* =========================================================================
* This file is originally part of the JMathTeX Library - http://jmathtex.sourceforge.net
*
* Copyright (C) 2004-2007 Universiteit Gent
* Copyright (C) 2009 DENIZET Calixte
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* A copy of the GNU General Public License can be found in the file
* LICENSE.txt provided with the source distribution of this program (see
* the META-INF directory in the source jar). This license can also be
* found on the GNU website at http://www.gnu.org/licenses/gpl.html.
*
* If you did not receive a copy of the GNU General Public License along
* with this program, contact the lead developer, or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Linking this library statically or dynamically with other modules
* is making a combined work based on this library. Thus, the terms
* and conditions of the GNU General Public License cover the whole
* combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce
* an executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under terms
* of your choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from or based
* on this library. If you modify this library, you may extend this exception
* to your version of the library, but you are not obliged to do so.
* If you do not wish to do so, delete this exception statement from your
* version.
*
*/
/* Modified by Calixte Denizet */
package com.himamis.retex.renderer.share;
/**
* An atom representing scripts to be attached to another atom.
*/
public class ScriptsAtom extends Atom {
// TeX constant: what's the use???
private final static SpaceAtom SCRIPT_SPACE = new SpaceAtom(TeXConstants.UNIT_POINT, 0.5f, 0, 0);
// base atom
private final Atom base;
// subscript and superscript to be attached to the base (if not null)
private final Atom subscript;
private final Atom superscript;
private int align = TeXConstants.ALIGN_LEFT;
@Override
final public Atom duplicate() {
return setFields(new ScriptsAtom(base, subscript, superscript, align == TeXConstants.ALIGN_LEFT));
}
public ScriptsAtom(Atom base, Atom sub, Atom sup) {
this.base = base;
subscript = sub;
superscript = sup;
}
public ScriptsAtom(Atom base, Atom sub, Atom sup, boolean left) {
this(base, sub, sup);
if (!left) {
align = TeXConstants.ALIGN_RIGHT;
}
}
@Override
public Box createBox(TeXEnvironment env) {
Box b = (base == null ? new StrutBox(0, 0, 0, 0) : base.createBox(env));
Box deltaSymbol = new StrutBox(0, 0, 0, 0);
if (subscript == null && superscript == null) {
return b;
}
TeXFont tf = env.getTeXFont();
int style = env.getStyle();
if (base.type_limits == TeXConstants.SCRIPT_LIMITS
|| (base.type_limits == TeXConstants.SCRIPT_NORMAL
&& style == TeXConstants.STYLE_DISPLAY)) {
return new UnderOverAtom(
new UnderOverAtom(base, subscript, TeXConstants.UNIT_POINT,
0.3f, true, false),
superscript, TeXConstants.UNIT_POINT, 3.0f, true, true)
.createBox(env);
}
HorizontalBox hor = new HorizontalBox(b);
int lastFontId = b.getLastFontId();
// if no last font found (whitespace box), use default "mu font"
if (lastFontId == TeXFont.NO_FONT) {
lastFontId = tf.getMuFontId();
}
TeXEnvironment subStyle = env.subStyle(), supStyle = env.supStyle();
// set delta and preliminary shift-up and shift-down values
double delta = 0, shiftUp, shiftDown;
// TODO: use polymorphism?
if (base instanceof AccentedAtom) { // special case :
// accent. This positions superscripts better next to the accent!
Box box = ((AccentedAtom) base).base.createBox(env.crampStyle());
shiftUp = box.getHeight() - tf.getSupDrop(supStyle.getStyle());
shiftDown = box.getDepth() + tf.getSubDrop(subStyle.getStyle());
} else if (base instanceof SymbolAtom
&& base.type == TeXConstants.TYPE_BIG_OPERATOR) { // single
// big
// operator
// symbol
Char c = tf.getChar(((SymbolAtom) base).getName(), style);
if (style < TeXConstants.STYLE_TEXT && tf.hasNextLarger(c)) {
// style
c = tf.getNextLarger(c, style);
}
Box x = new CharBox(c);
x.setShift(-(x.getHeight() + x.getDepth()) / 2
- env.getTeXFont().getAxisHeight(env.getStyle()));
hor = new HorizontalBox(x);
// include delta in width or not?
delta = c.getItalic();
deltaSymbol = new SpaceAtom(TeXConstants.MEDMUSKIP).createBox(env);
if (delta > TeXFormula.PREC && subscript == null) {
hor.add(new StrutBox(delta, 0, 0, 0));
}
shiftUp = hor.getHeight() - tf.getSupDrop(supStyle.getStyle());
shiftDown = hor.getDepth() + tf.getSubDrop(subStyle.getStyle());
} else if (base instanceof CharSymbol) {
shiftUp = shiftDown = 0;
CharFont cf = ((CharSymbol) base).getCharFont(tf);
if (!((CharSymbol) base).isMarkedAsTextSymbol()
|| !tf.hasSpace(cf.fontId)) {
delta = tf.getChar(cf, style).getItalic();
}
if (delta > TeXFormula.PREC && subscript == null) {
hor.add(new StrutBox(delta, 0, 0, 0));
delta = 0;
}
} else {
shiftUp = b.getHeight() - tf.getSupDrop(supStyle.getStyle());
shiftDown = b.getDepth() + tf.getSubDrop(subStyle.getStyle());
}
if (superscript == null) { // only subscript
Box x = subscript.createBox(subStyle);
// calculate and set shift amount
x.setShift(
Math.max(Math.max(shiftDown, tf.getSub1(style)),
x.getHeight() - 4
* Math.abs(tf.getXHeight(style, lastFontId))
/ 5));
hor.add(x);
hor.add(deltaSymbol);
return hor;
}
Box x = superscript.createBox(supStyle);
double msiz = x.getWidth();
if (subscript != null && align == TeXConstants.ALIGN_RIGHT) {
msiz = Math.max(msiz, subscript.createBox(subStyle).getWidth());
}
HorizontalBox sup = new HorizontalBox(x, msiz, align);
// add scriptspace (constant value!)
sup.add(SCRIPT_SPACE.createBox(env));
// adjust shift-up
double p;
if (style == TeXConstants.STYLE_DISPLAY) {
p = tf.getSup1(style);
} else if (env.crampStyle().getStyle() == style) {
p = tf.getSup3(style);
} else {
p = tf.getSup2(style);
}
shiftUp = Math.max(Math.max(shiftUp, p),
x.getDepth() + Math.abs(tf.getXHeight(style, lastFontId)) / 4);
if (subscript == null) { // only superscript
sup.setShift(-shiftUp);
hor.add(sup);
} else { // both superscript and subscript
Box y = subscript.createBox(subStyle);
HorizontalBox sub = new HorizontalBox(y, msiz, align);
// add scriptspace (constant value!)
sub.add(SCRIPT_SPACE.createBox(env));
// adjust shift-down
shiftDown = Math.max(shiftDown, tf.getSub2(style));
// position both sub- and superscript
double drt = tf.getDefaultRuleThickness(style);
double interSpace = shiftUp - x.getDepth() + shiftDown
- y.getHeight(); // space
// between
// sub-
// en
// superscript
if (interSpace < 4 * drt) { // too small
shiftUp += 4 * drt - interSpace;
// set bottom superscript at least 4/5 of X-height
// above
// baseline
double psi = 4 * Math.abs(tf.getXHeight(style, lastFontId)) / 5
- (shiftUp - x.getDepth());
if (psi > 0) {
shiftUp += psi;
shiftDown -= psi;
}
}
// create total box
VerticalBox vBox = new VerticalBox();
sup.setShift(delta);
vBox.add(sup);
// recalculate interspace
interSpace = shiftUp - x.getDepth() + shiftDown - y.getHeight();
vBox.add(new StrutBox(0, interSpace, 0, 0));
vBox.add(sub);
vBox.setHeight(shiftUp + x.getHeight());
vBox.setDepth(shiftDown + y.getDepth());
hor.add(vBox);
}
hor.add(deltaSymbol);
return hor;
}
@Override
public int getLeftType() {
return base.getLeftType();
}
@Override
public int getRightType() {
return base.getRightType();
}
public Atom getBase() {
return base;
}
public Atom getSub() {
return subscript;
}
public Atom getSup() {
return superscript;
}
}