001    /*
002     * Copyright 2002 - 2010 JEuclid, http://jeuclid.sf.net
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    /* $Id: LayoutTest.java,v 92b6a7c39d7f 2010/08/11 20:23:17 max $ */
018    
019    package net.sourceforge.jeuclid.test;
020    
021    import java.util.List;
022    
023    import net.sourceforge.jeuclid.DOMBuilder;
024    import net.sourceforge.jeuclid.MathMLParserSupport;
025    import net.sourceforge.jeuclid.elements.presentation.general.Mfrac;
026    import net.sourceforge.jeuclid.elements.presentation.token.Mi;
027    import net.sourceforge.jeuclid.elements.presentation.token.Mn;
028    import net.sourceforge.jeuclid.layout.JEuclidView;
029    import net.sourceforge.jeuclid.layout.LayoutStage;
030    import net.sourceforge.jeuclid.layout.LayoutableNode;
031    
032    import org.junit.Assert;
033    import org.junit.Test;
034    import org.w3c.dom.Node;
035    import org.w3c.dom.mathml.MathMLDocument;
036    import org.w3c.dom.mathml.MathMLFractionElement;
037    import org.w3c.dom.mathml.MathMLMathElement;
038    import org.w3c.dom.mathml.MathMLPresentationContainer;
039    import org.w3c.dom.mathml.MathMLPresentationToken;
040    import org.w3c.dom.views.DocumentView;
041    
042    /**
043     * @version $Revision: 92b6a7c39d7f $
044     */
045    public class LayoutTest {
046    
047        /**
048         * Test string with xml header.
049         */
050        final static public String TEST1 = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><math mode=\"display\">"
051                + "<mrow><mo>(</mo><mn>555</mn></mrow></math>";
052    
053        /**
054         * Test if there is something in the view.
055         *
056         * @throws Exception
057         *             if the test fails.
058         */
059        @Test
060        public void testViewNotEmpty() throws Exception {
061            final MathMLDocument docElement = DOMBuilder.getInstance()
062                    .createJeuclidDom(
063                            MathMLParserSupport.parseString(LayoutTest.TEST1));
064            final JEuclidView view = (JEuclidView) (((DocumentView) docElement)
065                    .getDefaultView());
066            Assert.assertTrue(
067                    "View has not enough ascent: " + view.getAscentHeight(),
068                    view.getAscentHeight() > 1.0f);
069            Assert.assertTrue("View has not enoguh width: " + view.getWidth(),
070                    view.getWidth() > 1.0f);
071            Assert.assertTrue("Descent Height < 0: " + view.getDescentHeight(),
072                    view.getDescentHeight() >= 0.0f);
073        }
074    
075        /**
076         * Tests if view modifies itself when DOM is modified.
077         *
078         * @throws Exception
079         *             if the test fails.
080         */
081        @Test
082        public void testViewMutable() throws Exception {
083            final MathMLDocument docElement = DOMBuilder.getInstance()
084                    .createJeuclidDom(
085                            MathMLParserSupport.parseString(LayoutTest.TEST1));
086            final JEuclidView view = (JEuclidView) (((DocumentView) docElement)
087                    .getDefaultView());
088    
089            final float oldAscent = view.getAscentHeight();
090            final float oldWidth = view.getWidth();
091    
092            final MathMLMathElement mathElement = (MathMLMathElement) docElement
093                    .getFirstChild();
094            final MathMLPresentationContainer mrow = (MathMLPresentationContainer) mathElement
095                    .getFirstChild();
096            final LayoutableNode mop = (LayoutableNode) mrow.getFirstChild();
097            final float oldmopascent = view.getInfo(mop).getAscentHeight(
098                    LayoutStage.STAGE2);
099    
100            final MathMLFractionElement mfrac = (MathMLFractionElement) docElement
101                    .createElement(Mfrac.ELEMENT);
102    
103            final MathMLPresentationToken denom = (MathMLPresentationToken) docElement
104                    .createElement(Mn.ELEMENT);
105    
106            denom.setTextContent("123");
107            mfrac.setDenominator(denom);
108            final MathMLPresentationToken nom = (MathMLPresentationToken) docElement
109                    .createElement(Mi.ELEMENT);
110            nom.setTextContent("X");
111            mfrac.setNumerator(nom);
112            mrow.appendChild(mfrac);
113    
114            Assert.assertTrue("Width of view should increase: " + view.getWidth()
115                    + " > " + oldWidth, view.getWidth() > oldWidth);
116            Assert.assertTrue(
117                    "Heightof view should increase: " + view.getAscentHeight()
118                            + " > " + oldAscent, view.getAscentHeight() > oldAscent);
119    
120            final float newmopascent = view.getInfo(mop).getAscentHeight(
121                    LayoutStage.STAGE2);
122            Assert.assertTrue("Operator should be larger: " + newmopascent + " > "
123                    + oldmopascent, newmopascent > oldmopascent);
124        }
125    
126        /**
127         * Test whitespace handling.
128         *
129         * @throws Exception
130         *             if the test fails.
131         */
132        @Test
133        public void testWhitespace() throws Exception {
134            final MathMLDocument docElement = DOMBuilder
135                    .getInstance()
136                    .createJeuclidDom(
137                            MathMLParserSupport
138                                    .parseString("<math><mtext>x x</mtext><mtext> x x </mtext><mtext>x    x</mtext></math>"));
139            final JEuclidView view = (JEuclidView) (((DocumentView) docElement)
140                    .getDefaultView());
141    
142            final MathMLMathElement mathElement = (MathMLMathElement) docElement
143                    .getFirstChild();
144            final LayoutableNode m1 = (LayoutableNode) mathElement
145                    .getFirstChild();
146            final LayoutableNode m2 = (LayoutableNode) m1.getNextSibling();
147            final LayoutableNode m3 = (LayoutableNode) m2.getNextSibling();
148    
149            // To trigger layout
150            view.getWidth();
151    
152            final float w1 = view.getInfo(m1).getWidth(LayoutStage.STAGE2);
153            final float w2 = view.getInfo(m2).getWidth(LayoutStage.STAGE2);
154            final float w3 = view.getInfo(m3).getWidth(LayoutStage.STAGE2);
155    
156            Assert.assertEquals("Whitespace around text should be trimmed to none",
157                    w2, w1, 0.01);
158            Assert.assertEquals("Whitespace inside text should be trimmed to 1",
159                    w3, w1, 0.01);
160    
161        }
162    
163        /**
164         * Test MO without math parent.
165         *
166         * @throws Exception
167         *             if the test fails.
168         */
169        @Test
170        public void testMoWithoutParent() throws Exception {
171            final MathMLDocument docElement = DOMBuilder
172                    .getInstance()
173                    .createJeuclidDom(
174                            MathMLParserSupport
175                                    .parseString("<mrow><mo>&#x2211;</mo></mrow>"));
176            final JEuclidView view = (JEuclidView) (((DocumentView) docElement)
177                    .getDefaultView());
178    
179            // To trigger layout
180            view.getWidth();
181        }
182    
183        /**
184         * Test MO without any parent.
185         *
186         * @throws Exception
187         *             if the test fails.
188         */
189        @Test
190        public void testMoWithoutParent2() throws Exception {
191            final MathMLDocument docElement = DOMBuilder.getInstance()
192                    .createJeuclidDom(
193                            MathMLParserSupport.parseString("<mo>&#x2211;</mo>"));
194            final JEuclidView view = (JEuclidView) (((DocumentView) docElement)
195                    .getDefaultView());
196    
197            // To trigger layout
198            view.getWidth();
199        }
200    
201        /**
202         * Test if getNodesAt() works.
203         *
204         * @throws Exception
205         *             if the test fails.
206         */
207        @Test
208        public void testGetNodesAt() throws Exception {
209            final MathMLDocument docElement = DOMBuilder.getInstance()
210                    .createJeuclidDom(
211                            MathMLParserSupport.parseString(LayoutTest.TEST1));
212            final JEuclidView view = (JEuclidView) (((DocumentView) docElement)
213                    .getDefaultView());
214            final List<JEuclidView.NodeRect> rlist = view.getNodesAt(15, 0, 0, 0);
215            Assert.assertSame(rlist.get(0).getNode(), docElement);
216            final Node math = docElement.getFirstChild();
217            Assert.assertSame(rlist.get(1).getNode(), math);
218            final Node mrow = math.getFirstChild();
219            Assert.assertSame(rlist.get(2).getNode(), mrow);
220            final Node five = mrow.getFirstChild().getNextSibling();
221            Assert.assertSame(rlist.get(3).getNode(), five);
222        }
223    }