/*
 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 4175418 8158924
 * @author John Raley
 * @summary This insures that bug 4175418: Font substitution in TextLayout /
 * LineBreakMeasurer is inconsistent has been fixed.  The problem was
 * that text was measured in one Font, but lines were produced
 * in a different font.
 */

/*
 * (C) Copyright IBM Corp. 1999, All Rights Reserved
 */

import java.text.AttributedString;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;

/**
 * This insures that bug 4175418: Font substitution in TextLayout /
 * LineBreakMeasurer is inconsistent has been fixed.  The problem was
 * that text was measured in one Font, but lines were produced
 * in a different font.  One symptom of this problem is that lines are
 * either too short or too long.  This test line-breaks a paragraph
 * and checks the line lengths to make sure breaks were chosen well.
 * This can be checked because the paragraph is so simple.
 */
public class TestLineBreakWithFontSub {

    public static void main(String[] args) {

        new TestLineBreakWithFontSub().test();
        System.out.println("Line break / font substitution test PASSED");
    }

    private static final String WORD = "word";
    private static final String SPACING = " ";
    // The Hebrew character in this string can trigger font substitution
    private static final String MIXED = "A\u05D0";

    private static final int NUM_WORDS = 12;

    private static final FontRenderContext DEFAULT_FRC =
                            new FontRenderContext(null, false, false);

    public void test() {

        // construct a paragraph as follows: MIXED + [SPACING + WORD] + ...
        StringBuffer text = new StringBuffer(MIXED);
        for (int i=0; i < NUM_WORDS; i++) {
            text.append(SPACING);
            text.append(WORD);
        }

        AttributedString attrString = new AttributedString(text.toString());
        attrString.addAttribute(TextAttribute.SIZE, new Float(24.0));

        LineBreakMeasurer measurer = new LineBreakMeasurer(attrString.getIterator(),
                                                           DEFAULT_FRC);

        // get width of a space-word sequence, in context
        int sequenceLength = WORD.length()+SPACING.length();
        measurer.setPosition(text.length() - sequenceLength);

        TextLayout layout = measurer.nextLayout(10000.0f);

        if (layout.getCharacterCount() != sequenceLength) {
            throw new Error("layout length is incorrect!");
        }

        final float sequenceAdvance = layout.getVisibleAdvance();

        float wrappingWidth = sequenceAdvance * 2;

        // now run test with a variety of widths
        while (wrappingWidth < (sequenceAdvance*NUM_WORDS)) {
            measurer.setPosition(0);
            checkMeasurer(measurer,
                          wrappingWidth,
                          sequenceAdvance,
                          text.length());
            wrappingWidth += sequenceAdvance / 5;
        }
    }

    /**
     * Iterate through measurer and check that every line is
     * not too long and not too short, but just right.
     */
    private void checkMeasurer(LineBreakMeasurer measurer,
                               float wrappingWidth,
                               float sequenceAdvance,
                               int endPosition) {

        do {
            TextLayout layout = measurer.nextLayout(wrappingWidth);
            float visAdvance = layout.getVisibleAdvance();

            // Check that wrappingWidth-sequenceAdvance < visAdvance
            // Also, if we're not at the end of the paragraph,
            // check that visAdvance <= wrappingWidth

            if (visAdvance > wrappingWidth) {
                // line is too long for given wrapping width
                throw new Error("layout is too long");
            }

            if (measurer.getPosition() < endPosition) {
                if (visAdvance <= wrappingWidth - sequenceAdvance) {
                    // line is too short for given wrapping width;
                    // another word would have fit
                    throw new Error("room for more words on line.  diff=" +
                                    (wrappingWidth - sequenceAdvance - visAdvance));
                }
            }
        } while (measurer.getPosition() != endPosition);
    }
}