mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +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 commit93ad4f06dd
This commit is contained in:
committed by
alexey.ushakov@jetbrains.com
parent
c624938627
commit
60d8918c3d
@@ -1607,7 +1607,12 @@ public abstract class AbstractDocument implements Document, Serializable {
|
||||
/**
|
||||
* Document property that indicates if a character has been inserted
|
||||
* 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";
|
||||
|
||||
|
||||
@@ -770,38 +770,8 @@ public class GlyphView extends View implements TabableView, Cloneable {
|
||||
private int getBreakSpot(int p0, int p1) {
|
||||
if (breakSpots == null) {
|
||||
// Re-calculate breakpoints for the whole view
|
||||
int start = getStartOffset();
|
||||
int end = getEndOffset();
|
||||
int[] bs = new int[end + 1 - start];
|
||||
int ix = 0;
|
||||
|
||||
// Breaker should work on the parent element because there may be
|
||||
// a valid breakpoint at the end edge of the view (space, etc.)
|
||||
Element parent = getElement().getParentElement();
|
||||
int pstart = (parent == null ? start : parent.getStartOffset());
|
||||
int pend = (parent == null ? end : parent.getEndOffset());
|
||||
|
||||
Segment s = getText(pstart, pend);
|
||||
s.first();
|
||||
BreakIterator breaker = getBreaker();
|
||||
breaker.setText(s);
|
||||
|
||||
// Backward search should start from end+1 unless there's NO end+1
|
||||
int startFrom = end + (pend > end ? 1 : 0);
|
||||
for (;;) {
|
||||
startFrom = breaker.preceding(s.offset + (startFrom - pstart))
|
||||
+ (pstart - s.offset);
|
||||
if (startFrom > start) {
|
||||
// The break spot is within the view
|
||||
bs[ix++] = startFrom;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SegmentCache.releaseSharedSegment(s);
|
||||
breakSpots = new int[ix];
|
||||
System.arraycopy(bs, 0, breakSpots, 0, ix);
|
||||
breakSpots = calcBreakSpots(breaker);
|
||||
}
|
||||
|
||||
int breakSpot = BreakIterator.DONE;
|
||||
@@ -817,6 +787,48 @@ public class GlyphView extends View implements TabableView, Cloneable {
|
||||
return breakSpot;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected int[] calcBreakSpots(BreakIterator breaker) {
|
||||
int start = getStartOffset();
|
||||
int end = getEndOffset();
|
||||
int[] bs = new int[end + 1 - start];
|
||||
int ix = 0;
|
||||
|
||||
// Breaker should work on the parent element because there may be
|
||||
// a valid breakpoint at the end edge of the view (space, etc.)
|
||||
Element parent = getElement().getParentElement();
|
||||
int pstart = (parent == null ? start : parent.getStartOffset());
|
||||
int pend = (parent == null ? end : parent.getEndOffset());
|
||||
|
||||
Segment s = getText(pstart, pend);
|
||||
s.first();
|
||||
breaker.setText(s);
|
||||
|
||||
// Backward search should start from end+1 unless there's NO end+1
|
||||
int startFrom = end + (pend > end ? 1 : 0);
|
||||
for (;;) {
|
||||
startFrom = breaker.preceding(s.offset + (startFrom - pstart))
|
||||
+ (pstart - s.offset);
|
||||
if (startFrom > start) {
|
||||
// The break spot is within the view
|
||||
bs[ix++] = startFrom;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SegmentCache.releaseSharedSegment(s);
|
||||
int[] result = new int[ix];
|
||||
System.arraycopy(bs, 0, result, 0, ix);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return break iterator appropriate for the current document.
|
||||
*
|
||||
|
||||
@@ -95,6 +95,7 @@ import javax.swing.text.View;
|
||||
* <li>list-style-image
|
||||
* <li>list-style-type
|
||||
* <li>list-style-position
|
||||
* <li>overflow-wrap
|
||||
* </ul>
|
||||
* The following are modeled, but currently not rendered.
|
||||
* <ul><li>font-variant
|
||||
@@ -492,6 +493,12 @@ public class CSS implements Serializable {
|
||||
public static final Attribute MARGIN_TOP =
|
||||
new Attribute("margin-top", "0", false);
|
||||
|
||||
/**
|
||||
* CSS attribute "overflow-wrap".
|
||||
*/
|
||||
public static final Attribute OVERFLOW_WRAP =
|
||||
new Attribute("overflow-wrap", "normal", true);
|
||||
|
||||
/**
|
||||
* CSS attribute "padding".
|
||||
*/
|
||||
@@ -595,7 +602,8 @@ public class CSS implements Serializable {
|
||||
PADDING_TOP, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM,
|
||||
VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH,
|
||||
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 =
|
||||
|
||||
@@ -1868,6 +1868,13 @@ public class HTMLDocument extends DefaultStyledDocument {
|
||||
*/
|
||||
private static final String I18NProperty = "i18n";
|
||||
|
||||
/**
|
||||
* Multi-byte property key.
|
||||
*
|
||||
* @see AbstractDocument#MultiByteProperty
|
||||
*/
|
||||
static final String MultiByteProperty = "multiByte";
|
||||
|
||||
static {
|
||||
contentAttributeSet = new SimpleAttributeSet();
|
||||
((MutableAttributeSet)contentAttributeSet).
|
||||
|
||||
@@ -26,6 +26,7 @@ package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.text.BreakIterator;
|
||||
import java.util.Locale;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.*;
|
||||
|
||||
@@ -61,6 +62,7 @@ public class InlineView extends LabelView {
|
||||
* @see View#insertUpdate
|
||||
*/
|
||||
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
wrapAnywhereMinimumSpan = -1;
|
||||
super.insertUpdate(e, a, f);
|
||||
}
|
||||
|
||||
@@ -77,6 +79,7 @@ public class InlineView extends LabelView {
|
||||
* @see View#removeUpdate
|
||||
*/
|
||||
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
wrapAnywhereMinimumSpan = -1;
|
||||
super.removeUpdate(e, a, f);
|
||||
}
|
||||
|
||||
@@ -90,6 +93,7 @@ public class InlineView extends LabelView {
|
||||
* @see View#changedUpdate
|
||||
*/
|
||||
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
wrapAnywhereMinimumSpan = -1;
|
||||
super.changedUpdate(e, a, f);
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
@@ -206,6 +210,8 @@ public class InlineView extends LabelView {
|
||||
nowrap = false;
|
||||
}
|
||||
|
||||
wrapAnywhere = "anywhere".equals(a.getAttribute(CSS.Attribute.OVERFLOW_WRAP));
|
||||
|
||||
HTMLDocument doc = (HTMLDocument)getDocument();
|
||||
// fetches background color from stylesheet if specified
|
||||
Color bg = doc.getBackground(a);
|
||||
@@ -224,6 +230,41 @@ public class InlineView extends LabelView {
|
||||
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 = calcBreakSpots(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 AttributeSet attr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user