1 /*
2 * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
63 private static final Object CACHE_SIZE_LOCK = new Object();
64 private static int cacheSize = 0;
65 private static final int MAX_STRING_SIZE = 256;
66 private static final int MAX_CACHE_SIZE = PrismFontFactory.cacheLayoutSize;
67
68 private char[] text;
69 private TextSpan[] spans; /* Rich text (null for single font text) */
70 private PGFont font; /* Single font text (null for rich text) */
71 private FontStrike strike; /* cached strike of font (identity) */
72 private Integer cacheKey;
73 private TextLine[] lines;
74 private TextRun[] runs;
75 private int runCount;
76 private BaseBounds logicalBounds;
77 private RectBounds visualBounds;
78 private float layoutWidth, layoutHeight;
79 private float wrapWidth, spacing;
80 private LayoutCache layoutCache;
81 private Shape shape;
82 private int flags;
83
84 public PrismTextLayout() {
85 logicalBounds = new RectBounds();
86 flags = ALIGN_LEFT;
87 }
88
89 private void reset() {
90 layoutCache = null;
91 runs = null;
92 flags &= ~ANALYSIS_MASK;
93 relayout();
94 }
95
96 private void relayout() {
97 logicalBounds.makeEmpty();
98 visualBounds = null;
99 layoutWidth = layoutHeight = 0;
100 flags &= ~(FLAGS_WRAPPED | FLAGS_CACHED_UNDERLINE | FLAGS_CACHED_STRIKETHROUGH);
101 lines = null;
102 shape = null;
631 rect.x = runX;
632 rect.y = runY + metrics.getStrikethroughOffset();
633 rect.width = run.getWidth();
634 rect.height = metrics.getStrikethroughThickness();
635 outline.append(rect, false);
636 }
637 if (text && run.getGlyphCount() > 0) {
638 tx.restoreTransform(1, 0, 0, 1, runX, runY);
639 Path2D path = (Path2D)fontStrike.getOutline(run, tx);
640 outline.append(path, false);
641 }
642 }
643 }
644
645 if (text && !underline && !strikethrough) {
646 shape = outline;
647 }
648 return outline;
649 }
650
651 /***************************************************************************
652 * *
653 * Text Layout Implementation *
654 * *
655 **************************************************************************/
656
657 private int getLineIndex(float y) {
658 int index = 0;
659 float bottom = 0;
660 int lineCount = getLineCount();
661 while (index < lineCount) {
662 bottom += lines[index].getBounds().getHeight() + spacing;
663 if (index + 1 == lineCount) bottom -= lines[index].getLeading();
664 if (bottom > y) break;
665 index++;
666 }
667 return index;
668 }
669
670 private boolean copyCache() {
987 }
988 }
989 }
990
991 private float getTabAdvance() {
992 float spaceAdvance = 0;
993 if (spans != null) {
994 /* Rich text case - use the first font (for now) */
995 for (int i = 0; i < spans.length; i++) {
996 TextSpan span = spans[i];
997 PGFont font = (PGFont)span.getFont();
998 if (font != null) {
999 FontStrike strike = font.getStrike(IDENTITY);
1000 spaceAdvance = strike.getCharAdvance(' ');
1001 break;
1002 }
1003 }
1004 } else {
1005 spaceAdvance = strike.getCharAdvance(' ');
1006 }
1007 return 8 * spaceAdvance;
1008 }
1009
1010 private void layout() {
1011 /* Try the cache */
1012 initCache();
1013
1014 /* Whole layout retrieved from the cache */
1015 if (lines != null) return;
1016 char[] chars = getText();
1017
1018 /* runs and runCount are set in reuseRuns or buildRuns */
1019 if ((flags & FLAGS_ANALYSIS_VALID) != 0 && isSimpleLayout()) {
1020 reuseRuns();
1021 } else {
1022 buildRuns(chars);
1023 }
1024
1025 GlyphLayout layout = null;
1026 if ((flags & (FLAGS_HAS_COMPLEX)) != 0) {
1027 layout = GlyphLayout.getInstance();
|
1 /*
2 * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
63 private static final Object CACHE_SIZE_LOCK = new Object();
64 private static int cacheSize = 0;
65 private static final int MAX_STRING_SIZE = 256;
66 private static final int MAX_CACHE_SIZE = PrismFontFactory.cacheLayoutSize;
67
68 private char[] text;
69 private TextSpan[] spans; /* Rich text (null for single font text) */
70 private PGFont font; /* Single font text (null for rich text) */
71 private FontStrike strike; /* cached strike of font (identity) */
72 private Integer cacheKey;
73 private TextLine[] lines;
74 private TextRun[] runs;
75 private int runCount;
76 private BaseBounds logicalBounds;
77 private RectBounds visualBounds;
78 private float layoutWidth, layoutHeight;
79 private float wrapWidth, spacing;
80 private LayoutCache layoutCache;
81 private Shape shape;
82 private int flags;
83 private int tabSize = DEFAULT_TAB_SIZE;
84
85 public PrismTextLayout() {
86 logicalBounds = new RectBounds();
87 flags = ALIGN_LEFT;
88 }
89
90 private void reset() {
91 layoutCache = null;
92 runs = null;
93 flags &= ~ANALYSIS_MASK;
94 relayout();
95 }
96
97 private void relayout() {
98 logicalBounds.makeEmpty();
99 visualBounds = null;
100 layoutWidth = layoutHeight = 0;
101 flags &= ~(FLAGS_WRAPPED | FLAGS_CACHED_UNDERLINE | FLAGS_CACHED_STRIKETHROUGH);
102 lines = null;
103 shape = null;
632 rect.x = runX;
633 rect.y = runY + metrics.getStrikethroughOffset();
634 rect.width = run.getWidth();
635 rect.height = metrics.getStrikethroughThickness();
636 outline.append(rect, false);
637 }
638 if (text && run.getGlyphCount() > 0) {
639 tx.restoreTransform(1, 0, 0, 1, runX, runY);
640 Path2D path = (Path2D)fontStrike.getOutline(run, tx);
641 outline.append(path, false);
642 }
643 }
644 }
645
646 if (text && !underline && !strikethrough) {
647 shape = outline;
648 }
649 return outline;
650 }
651
652 @Override
653 public boolean setTabSize(int spaces) {
654 if (spaces < 1)
655 spaces = 1;
656 if (tabSize != spaces) {
657 tabSize = spaces;
658 relayout();
659 return true;
660 }
661 return false;
662 }
663
664 /***************************************************************************
665 * *
666 * Text Layout Implementation *
667 * *
668 **************************************************************************/
669
670 private int getLineIndex(float y) {
671 int index = 0;
672 float bottom = 0;
673 int lineCount = getLineCount();
674 while (index < lineCount) {
675 bottom += lines[index].getBounds().getHeight() + spacing;
676 if (index + 1 == lineCount) bottom -= lines[index].getLeading();
677 if (bottom > y) break;
678 index++;
679 }
680 return index;
681 }
682
683 private boolean copyCache() {
1000 }
1001 }
1002 }
1003
1004 private float getTabAdvance() {
1005 float spaceAdvance = 0;
1006 if (spans != null) {
1007 /* Rich text case - use the first font (for now) */
1008 for (int i = 0; i < spans.length; i++) {
1009 TextSpan span = spans[i];
1010 PGFont font = (PGFont)span.getFont();
1011 if (font != null) {
1012 FontStrike strike = font.getStrike(IDENTITY);
1013 spaceAdvance = strike.getCharAdvance(' ');
1014 break;
1015 }
1016 }
1017 } else {
1018 spaceAdvance = strike.getCharAdvance(' ');
1019 }
1020 return tabSize * spaceAdvance;
1021 }
1022
1023 private void layout() {
1024 /* Try the cache */
1025 initCache();
1026
1027 /* Whole layout retrieved from the cache */
1028 if (lines != null) return;
1029 char[] chars = getText();
1030
1031 /* runs and runCount are set in reuseRuns or buildRuns */
1032 if ((flags & FLAGS_ANALYSIS_VALID) != 0 && isSimpleLayout()) {
1033 reuseRuns();
1034 } else {
1035 buildRuns(chars);
1036 }
1037
1038 GlyphLayout layout = null;
1039 if ((flags & (FLAGS_HAS_COMPLEX)) != 0) {
1040 layout = GlyphLayout.getInstance();
|