mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-17 06:49:42 +01:00
JBR-2234 Support CSS setting overflow-wrap:anywhere in JEditorPane
port from JBR 11 to JBR 15 (cherry picked from commitsb6583d0a71,6003abc15f) cherry picked from commit93ad4f06ddalso includes JBR-4006 [JCK] javax.swing.text.html.CSS$Attribute.OVERFLOW_WRAP field breaks public API (cherry picked from commitf20a3d8679) and JBR-4007 [JCK] javax.swing.text.GlyphView.calcBreakSpots method breaks public API (cherry picked from commit1002eff4f3) (cherry picked from commitf603f9e837)
This commit is contained in:
@@ -1601,7 +1601,12 @@ public abstract class AbstractDocument implements Document, Serializable {
|
|||||||
/**
|
/**
|
||||||
* Document property that indicates if a character has been inserted
|
* Document property that indicates if a character has been inserted
|
||||||
* into the document that is more than one byte long. GlyphView uses
|
* into the document that is more than one byte long. GlyphView uses
|
||||||
* this to determine if it should use BreakIterator.
|
* this to determine if it should use BreakIterator. This property should
|
||||||
|
* not be publicly exposed, since it is used for implementation convenience
|
||||||
|
* only. As a side effect, copies of this property may be in its subclasses
|
||||||
|
* that live in different packages (e.g. HTMLDocument as of now), so those
|
||||||
|
* copies should also be taken care of when this property needs to be
|
||||||
|
* modified.
|
||||||
*/
|
*/
|
||||||
static final Object MultiByteProperty = "multiByte";
|
static final Object MultiByteProperty = "multiByte";
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import java.util.Locale;
|
|||||||
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import sun.swing.SwingUtilities2;
|
import sun.swing.SwingUtilities2;
|
||||||
|
import sun.swing.text.GlyphViewAccessor;
|
||||||
|
|
||||||
import static sun.swing.SwingUtilities2.IMPLIED_CR;
|
import static sun.swing.SwingUtilities2.IMPLIED_CR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -777,6 +779,41 @@ public class GlyphView extends View implements TabableView, Cloneable {
|
|||||||
private int getBreakSpot(int p0, int p1) {
|
private int getBreakSpot(int p0, int p1) {
|
||||||
if (breakSpots == null) {
|
if (breakSpots == null) {
|
||||||
// Re-calculate breakpoints for the whole view
|
// Re-calculate breakpoints for the whole view
|
||||||
|
BreakIterator breaker = getBreaker();
|
||||||
|
breakSpots = calcBreakSpots(breaker);
|
||||||
|
}
|
||||||
|
|
||||||
|
int breakSpot = BreakIterator.DONE;
|
||||||
|
for (int i = 0; i < breakSpots.length; i++) {
|
||||||
|
int bsp = breakSpots[i];
|
||||||
|
if (bsp <= p1) {
|
||||||
|
if (bsp > p0) {
|
||||||
|
breakSpot = bsp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return breakSpot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
GlyphViewAccessor.setAccessor(new GlyphViewAccessor() {
|
||||||
|
@Override
|
||||||
|
public int[] calcBreakSpots(GlyphView glyphView, BreakIterator breaker) {
|
||||||
|
return glyphView.calcBreakSpots(breaker);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: convert to protected method (removing accessor) when upstreaming the fix
|
||||||
|
/**
|
||||||
|
* Collects all possible breaking positions in the element,
|
||||||
|
* generated by the provided breaker.
|
||||||
|
*
|
||||||
|
* @param breaker provider of break positions
|
||||||
|
* @return possible break positions in the element
|
||||||
|
*/
|
||||||
|
int[] calcBreakSpots(BreakIterator breaker) {
|
||||||
int start = getStartOffset();
|
int start = getStartOffset();
|
||||||
int end = getEndOffset();
|
int end = getEndOffset();
|
||||||
int[] bs = new int[end + 1 - start];
|
int[] bs = new int[end + 1 - start];
|
||||||
@@ -790,7 +827,6 @@ public class GlyphView extends View implements TabableView, Cloneable {
|
|||||||
|
|
||||||
Segment s = getText(pstart, pend);
|
Segment s = getText(pstart, pend);
|
||||||
s.first();
|
s.first();
|
||||||
BreakIterator breaker = getBreaker();
|
|
||||||
breaker.setText(s);
|
breaker.setText(s);
|
||||||
|
|
||||||
// Backward search should start from end+1 unless there's NO end+1
|
// Backward search should start from end+1 unless there's NO end+1
|
||||||
@@ -807,21 +843,9 @@ public class GlyphView extends View implements TabableView, Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SegmentCache.releaseSharedSegment(s);
|
SegmentCache.releaseSharedSegment(s);
|
||||||
breakSpots = new int[ix];
|
int[] result = new int[ix];
|
||||||
System.arraycopy(bs, 0, breakSpots, 0, ix);
|
System.arraycopy(bs, 0, result, 0, ix);
|
||||||
}
|
return result;
|
||||||
|
|
||||||
int breakSpot = BreakIterator.DONE;
|
|
||||||
for (int i = 0; i < breakSpots.length; i++) {
|
|
||||||
int bsp = breakSpots[i];
|
|
||||||
if (bsp <= p1) {
|
|
||||||
if (bsp > p0) {
|
|
||||||
breakSpot = bsp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return breakSpot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ import javax.swing.text.View;
|
|||||||
* <li>list-style-image
|
* <li>list-style-image
|
||||||
* <li>list-style-type
|
* <li>list-style-type
|
||||||
* <li>list-style-position
|
* <li>list-style-position
|
||||||
|
* <li>overflow-wrap
|
||||||
* </ul>
|
* </ul>
|
||||||
* The following are modeled, but currently not rendered.
|
* The following are modeled, but currently not rendered.
|
||||||
* <ul><li>font-variant
|
* <ul><li>font-variant
|
||||||
@@ -495,6 +496,14 @@ public class CSS implements Serializable {
|
|||||||
public static final Attribute MARGIN_TOP =
|
public static final Attribute MARGIN_TOP =
|
||||||
new Attribute("margin-top", "0", false);
|
new Attribute("margin-top", "0", false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS attribute "overflow-wrap".
|
||||||
|
*
|
||||||
|
* TODO: make public when upstreaming the fix
|
||||||
|
*/
|
||||||
|
static final Attribute OVERFLOW_WRAP =
|
||||||
|
new Attribute("overflow-wrap", "normal", true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSS attribute "padding".
|
* CSS attribute "padding".
|
||||||
*/
|
*/
|
||||||
@@ -598,7 +607,8 @@ public class CSS implements Serializable {
|
|||||||
PADDING_TOP, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM,
|
PADDING_TOP, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM,
|
||||||
VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH,
|
VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH,
|
||||||
BORDER_SPACING, CAPTION_SIDE,
|
BORDER_SPACING, CAPTION_SIDE,
|
||||||
MARGIN_LEFT_LTR, MARGIN_LEFT_RTL, MARGIN_RIGHT_LTR, MARGIN_RIGHT_RTL
|
MARGIN_LEFT_LTR, MARGIN_LEFT_RTL, MARGIN_RIGHT_LTR, MARGIN_RIGHT_RTL,
|
||||||
|
OVERFLOW_WRAP
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final Attribute[] ALL_MARGINS =
|
private static final Attribute[] ALL_MARGINS =
|
||||||
|
|||||||
@@ -1894,6 +1894,13 @@ public class HTMLDocument extends DefaultStyledDocument {
|
|||||||
*/
|
*/
|
||||||
private static final String I18NProperty = "i18n";
|
private static final String I18NProperty = "i18n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-byte property key.
|
||||||
|
*
|
||||||
|
* @see AbstractDocument#MultiByteProperty
|
||||||
|
*/
|
||||||
|
static final String MultiByteProperty = "multiByte";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
contentAttributeSet = new SimpleAttributeSet();
|
contentAttributeSet = new SimpleAttributeSet();
|
||||||
((MutableAttributeSet)contentAttributeSet).
|
((MutableAttributeSet)contentAttributeSet).
|
||||||
|
|||||||
@@ -24,8 +24,11 @@
|
|||||||
*/
|
*/
|
||||||
package javax.swing.text.html;
|
package javax.swing.text.html;
|
||||||
|
|
||||||
|
import sun.swing.text.GlyphViewAccessor;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.text.BreakIterator;
|
import java.text.BreakIterator;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.text.*;
|
import javax.swing.text.*;
|
||||||
|
|
||||||
@@ -61,6 +64,7 @@ public class InlineView extends LabelView {
|
|||||||
* @see View#insertUpdate
|
* @see View#insertUpdate
|
||||||
*/
|
*/
|
||||||
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||||
|
wrapAnywhereMinimumSpan = -1;
|
||||||
super.insertUpdate(e, a, f);
|
super.insertUpdate(e, a, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +81,7 @@ public class InlineView extends LabelView {
|
|||||||
* @see View#removeUpdate
|
* @see View#removeUpdate
|
||||||
*/
|
*/
|
||||||
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||||
|
wrapAnywhereMinimumSpan = -1;
|
||||||
super.removeUpdate(e, a, f);
|
super.removeUpdate(e, a, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +95,7 @@ public class InlineView extends LabelView {
|
|||||||
* @see View#changedUpdate
|
* @see View#changedUpdate
|
||||||
*/
|
*/
|
||||||
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||||
|
wrapAnywhereMinimumSpan = -1;
|
||||||
super.changedUpdate(e, a, f);
|
super.changedUpdate(e, a, f);
|
||||||
StyleSheet sheet = getStyleSheet();
|
StyleSheet sheet = getStyleSheet();
|
||||||
attr = sheet.getViewAttributes(this);
|
attr = sheet.getViewAttributes(this);
|
||||||
@@ -206,6 +212,8 @@ public class InlineView extends LabelView {
|
|||||||
nowrap = false;
|
nowrap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrapAnywhere = "anywhere".equals(a.getAttribute(CSS.Attribute.OVERFLOW_WRAP));
|
||||||
|
|
||||||
HTMLDocument doc = (HTMLDocument)getDocument();
|
HTMLDocument doc = (HTMLDocument)getDocument();
|
||||||
// fetches background color from stylesheet if specified
|
// fetches background color from stylesheet if specified
|
||||||
Color bg = doc.getBackground(a);
|
Color bg = doc.getBackground(a);
|
||||||
@@ -224,6 +232,41 @@ public class InlineView extends LabelView {
|
|||||||
return doc.getStyleSheet();
|
return doc.getStyleSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMinimumSpan(int axis) {
|
||||||
|
if (axis == View.X_AXIS && wrapAnywhere) {
|
||||||
|
if (wrapAnywhereMinimumSpan < 0) {
|
||||||
|
wrapAnywhereMinimumSpan = 0;
|
||||||
|
int startOffset = getStartOffset();
|
||||||
|
int endOffset = getEndOffset();
|
||||||
|
Document doc = getDocument();
|
||||||
|
if ((doc != null) && Boolean.TRUE.equals(doc.getProperty(HTMLDocument.MultiByteProperty))) {
|
||||||
|
Container c = getContainer();
|
||||||
|
Locale locale = (c == null ? Locale.getDefault() : c.getLocale());
|
||||||
|
BreakIterator breaker = BreakIterator.getCharacterInstance(locale);
|
||||||
|
int[] breakSpots = GlyphViewAccessor.getAccessor().calcBreakSpots(this, breaker);
|
||||||
|
int lastBreak = endOffset;
|
||||||
|
for (int breakSpot : breakSpots) {
|
||||||
|
wrapAnywhereMinimumSpan = Math.max(wrapAnywhereMinimumSpan,
|
||||||
|
getPartialSpan(breakSpot, lastBreak));
|
||||||
|
lastBreak = breakSpot;
|
||||||
|
}
|
||||||
|
wrapAnywhereMinimumSpan = Math.max(wrapAnywhereMinimumSpan,
|
||||||
|
getPartialSpan(startOffset, lastBreak));
|
||||||
|
} else {
|
||||||
|
for (int i = startOffset ; i < endOffset; i++) {
|
||||||
|
wrapAnywhereMinimumSpan = Math.max(wrapAnywhereMinimumSpan,
|
||||||
|
getPartialSpan(i, i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wrapAnywhereMinimumSpan;
|
||||||
|
}
|
||||||
|
return super.getMinimumSpan(axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float wrapAnywhereMinimumSpan = -1;
|
||||||
|
private boolean wrapAnywhere;
|
||||||
private boolean nowrap;
|
private boolean nowrap;
|
||||||
private AttributeSet attr;
|
private AttributeSet attr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 JetBrains s.r.o.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.swing.text;
|
||||||
|
|
||||||
|
import javax.swing.text.GlyphView;
|
||||||
|
import java.text.BreakIterator;
|
||||||
|
|
||||||
|
public abstract class GlyphViewAccessor {
|
||||||
|
private static GlyphViewAccessor accessor;
|
||||||
|
|
||||||
|
public static void setAccessor(GlyphViewAccessor a) {
|
||||||
|
accessor = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlyphViewAccessor getAccessor() {
|
||||||
|
return accessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int[] calcBreakSpots(GlyphView glyphView, BreakIterator breaker);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user