IDEA-346213 QuickDoc: improve wrapping of long qualified names and URLs

GitOrigin-RevId: c808dd4c333636dc9dc36e01b3afa57f3037ec0c
This commit is contained in:
Piotr Tomiak
2024-02-15 10:48:47 +01:00
committed by intellij-monorepo-bot
parent 8470728a07
commit a028674bdb
20 changed files with 260 additions and 66 deletions

View File

@@ -15,8 +15,8 @@
<!-- -->
</a>
<ul class="blockListLast">
<h3><a href="psi_element://com.jetbrains.GenericClass"><code>com.jetbrains.GenericClass</code></a></h3>
<pre>public&nbsp;void&nbsp;genericMethod(java.lang.Class&lt;?&gt;&nbsp;clazz)</pre>
<h3><a href="psi_element://com.jetbrains.GenericClass"><code>com.<wbr>jetbrains.<wbr>GenericClass</code></a></h3>
<pre>public&nbsp;void&nbsp;genericMethod(java.<wbr>lang.<wbr>Class&lt;?&gt;&nbsp;clazz)</pre>
<div class="block">javadoc</div>
</li>
</ul>

View File

@@ -14,7 +14,7 @@
</style><div class='content'><a name="m1--">
<!-- -->
</a>
<h3><a href="psi_element://com.jetbrains.LinkBetweenMethods"><code>com.jetbrains.LinkBetweenMethods</code></a></h3>
<h3><a href="psi_element://com.jetbrains.LinkBetweenMethods"><code>com.<wbr>jetbrains.<wbr>LinkBetweenMethods</code></a></h3>
<pre>public&nbsp;void&nbsp;m1()</pre>
<div class="block"><a href="psi_element://com.jetbrains.LinkBetweenMethods#m2()"><code>m2()</code></a></div>
</li>

View File

@@ -13,7 +13,7 @@
}
</style><div class='content'><!-- ======== START OF CLASS DATA ======== -->
<div class="header">
<div class="subTitle">com.jetbrains</div>
<div class="subTitle">com.<wbr>jetbrains</div>
<h2 title="Interface SimpleInterface" class="title">Interface SimpleInterface</h2>
</div>
<div class="contentContainer">

View File

@@ -13,21 +13,21 @@
}
</style><div class='content'><!-- ======== START OF CLASS DATA ======== -->
<div class="header">
<div class="subTitle">com.jetbrains</div>
<div class="subTitle">com.<wbr>jetbrains</div>
<h2 title="Class ClassWithRefLink" class="title">Class ClassWithRefLink</h2>
</div>
<div class="contentContainer">
<ul class="inheritance">
<li>java.lang.Object</li>
<li>java.<wbr>lang.<wbr>Object</li>
<li>
<ul class="inheritance">
<li>com.jetbrains.ClassWithRefLink</li>
<li>com.<wbr>jetbrains.<wbr>ClassWithRefLink</li>
</ul>
</li>
</ul>
<DL><br>
<pre>public class <span class="typeNameLabel">ClassWithRefLink</span>
extends java.lang.Object</pre>
extends java.<wbr>lang.<wbr>Object</pre>
<div class="block"><a href="psi_element://com.jetbrains.Test###someRef">link</a></div>
</li>
</ul>

View File

@@ -15,8 +15,8 @@
<!-- -->
</a>
<ul class="blockListLast">
<h3><a href="psi_element://com.jetbrains.TestAnnotation"><code>com.jetbrains.TestAnnotation</code></a></h3>
<pre>public abstract&nbsp;java.lang.String&nbsp;param</pre>
<h3><a href="psi_element://com.jetbrains.TestAnnotation"><code>com.<wbr>jetbrains.<wbr>TestAnnotation</code></a></h3>
<pre>public abstract&nbsp;java.<wbr>lang.<wbr>String&nbsp;param</pre>
<div class="block">Some info and a <a href="psi_element://com.jetbrains.Test">link</a></div>
</li>
</ul>

View File

@@ -1,8 +1,8 @@
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://java.util.List"><code><span style="color:#000000;">java.util.List</span><span style="">&lt;</span><span style="color:#20999d;">E</span><span style="">&gt;</span></code></a></div><div class='definition-separated'><pre><span style="color:#808000;">@</span><span style="color:#808000;">Contract</span><span style="">(</span><span style="">pure</span><span style=""> = </span><span style="color:#000080;font-weight:bold;">true</span><span style="">)</span><a href="external.annotations"><icon src="AllIcons.Ide.External_link_arrow"></a>&nbsp;
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://java.util.List"><code><span style="color:#000000;">java.<wbr>util.<wbr>List</span><span style="">&lt;</span><span style="color:#20999d;">E</span><span style="">&gt;</span></code></a></div><div class='definition-separated'><pre><span style="color:#808000;">@</span><span style="color:#808000;">Contract</span><span style="">(</span><span style="">pure</span><span style=""> = </span><span style="color:#000080;font-weight:bold;">true</span><span style="">)</span><a href="external.annotations"><icon src="AllIcons.Ide.External_link_arrow"></a>&nbsp;
<span style="color:#000080;font-weight:bold;">public abstract</span>&nbsp;<span style="color:#000080;font-weight:bold;">boolean</span>&nbsp;<span style="color:#000000;">contains</span><span style="">(</span><br> <a href="psi_element://java.lang.Object"><code><span style="color:#000000;">Object</span></code></a>&nbsp;<span style="color:#000000;">o</span><br><span style="">)</span></pre></div><div class='content'>
<p>Returns <tt>true</tt> if this list contains the specified element.
More formally, returns <tt>true</tt> if and only if this list contains
at least one element <tt>e</tt> such that
<tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
<tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.<wbr>equals(e))</tt>.
</div><table class='sections'><tr><td valign='top' class='section'><p>Overrides:</td><td valign='top'><p><a href="psi_element://java.util.Collection#contains(java.lang.Object)"><code><span style="color:#000000;">contains</span></code></a> in interface <a href="psi_element://java.util.Collection"><code><span style="color:#000000;">Collection</span></code></a></td><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><code><span style="color:#000000;">o</span></code> &ndash; element whose presence in this list is to be tested </td><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p><tt>true</tt> if this list contains the specified element </td><tr><td valign='top' class='section'><p>Throws:</td><td valign='top'><p><a href="psi_element://java.lang.ClassCastException"><code><span style="color:#0000ff;">ClassCastException</span></code></a> &ndash; if the type of the specified element is incompatible with this list (<a href="psi_element://java.util.Collection###optional-restrictions">optional</a>) <p><a href="psi_element://java.lang.NullPointerException"><code><span style="color:#0000ff;">NullPointerException</span></code></a> &ndash; if the specified element is null and this list does not permit null elements (<a href="psi_element://java.util.Collection###optional-restrictions">optional</a>)</td></table><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/>&nbsp;&lt; java 1.7 &gt;</div>

View File

@@ -1,9 +1,9 @@
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://My"><code><span style="color:#000000;">My</span></code></a></div><div class='definition-separated'><pre><i><span style="color:#808000;">@</span><a href="psi_element://org.jetbrains.annotations.Contract"><code><span style="color:#808000;">Contract</span></code></a><span style="">(</span><span style="">pure</span><span style=""> = </span><span style="color:#000080;font-weight:bold;">true</span><span style="">)</span></i><sup><font color="808080" size="3"><i>i</i></font></sup><a href="inferred.annotations"><icon src="AllIcons.Ide.External_link_arrow"></a>&nbsp;
<span style="color:#000080;font-weight:bold;">boolean</span>&nbsp;<span style="color:#000000;">contains</span><span style="">(</span><br> <a href="psi_element://java.lang.Object"><code><span style="color:#000000;">Object</span></code></a>&nbsp;<span style="color:#000000;">o</span><br><span style="">)</span>
<span style="color:#000080;font-weight:bold;">throws</span>&nbsp;<span style="color:#ff0000">IOException</span></pre></div><table class='sections'><tr><td valign='top' class='section'><p>From interface:</td><td valign='top'><p><a href="psi_element://java.util.Collection"><code><span style="color:#000000;">java.util.Collection</span></code></a><br>
<span style="color:#000080;font-weight:bold;">throws</span>&nbsp;<span style="color:#ff0000">IOException</span></pre></div><table class='sections'><tr><td valign='top' class='section'><p>From interface:</td><td valign='top'><p><a href="psi_element://java.util.Collection"><code><span style="color:#000000;">java.<wbr>util.<wbr>Collection</span></code></a><br>
Returns <tt>true</tt> if this collection contains the specified element.
More formally, returns <tt>true</tt> if and only if this collection
contains at least one element <tt>e</tt> such that
<tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
<tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.<wbr>equals(e))</tt>.
</td><tr><td valign='top' class='section'><p>Overrides:</td><td valign='top'><p><a href="psi_element://java.util.Collection#contains(java.lang.Object)"><code><span style="color:#000000;">contains</span></code></a> in interface <a href="psi_element://java.util.Collection"><code><span style="color:#000000;">Collection</span></code></a><br><a href="psi_element://I#contains(java.lang.Object)"><code><span style="color:#000000;">contains</span></code></a> in interface <a href="psi_element://I"><code><span style="color:#000000;">I</span></code></a></td><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><code><span style="color:#000000;">o</span></code> &ndash; element whose presence in this collection is to be tested </td><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p><tt>true</tt> if this collection contains the specified element </td><tr><td valign='top' class='section'><p>Throws:</td><td valign='top'><p><a href="psi_element://java.lang.NullPointerException"><code><span style="color:#0000ff;">NullPointerException</span></code></a> &ndash; before if the specified element is null and this collection does not permit null elements (<a href="psi_element://My###optional-restrictions">optional</a>) after<p><span style="color:#ff0000">IOException</span></td></table>

View File

@@ -1,4 +1,4 @@
<html><head><base href="placeholder"></head><body><div class='definition-separated'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">C</span></pre></div><div class='content'>
<p>some text
</div><table class='sections'><tr><td valign='top' class='section'><p>See Also:</td><td valign='top'><p>System.out</td></table>
</div><table class='sections'><tr><td valign='top' class='section'><p>See Also:</td><td valign='top'><p>System.<wbr>out</td></table>

View File

@@ -1,3 +1,3 @@
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>packageInfoWithCopyright</code></div><div class='content'>
<p>This package contains nothing but package-info.java
<p>This package contains nothing but package-info.<wbr>java
</div>

View File

@@ -1,5 +1,5 @@
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://java.lang.Class"><code><span style="color:#000000;">java.lang.Class</span><span style="">&lt;</span><span style="color:#20999d;">T</span><span style="">&gt;</span></code></a></div><div class='definition-separated'><pre><span style="color:#ff0000">@<span style="color:#808000;">CallerSensitive</span></span>&nbsp;
<html><head><base href="placeholder"></head><body><div class="bottom"><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://java.lang.Class"><code><span style="color:#000000;">java.<wbr>lang.<wbr>Class</span><span style="">&lt;</span><span style="color:#20999d;">T</span><span style="">&gt;</span></code></a></div><div class='definition-separated'><pre><span style="color:#ff0000">@<span style="color:#808000;">CallerSensitive</span></span>&nbsp;
<span style="color:#808000;">@</span><span style="color:#808000;">NotNull</span><a href="external.annotations"><icon src="AllIcons.Ide.External_link_arrow"></a>&nbsp;
<span style="color:#808000;">@</span><span style="color:#808000;">Contract</span><span style="">(</span><span style="">pure</span><span style=""> = </span><span style="color:#000080;font-weight:bold;">true</span><span style="">)</span><a href="external.annotations"><icon src="AllIcons.Ide.External_link_arrow"></a>&nbsp;
<span style="color:#000080;font-weight:bold;">public</span>&nbsp;<a href="psi_element://java.lang.reflect.Constructor"><code><span style="color:#000000;">java.lang.reflect.Constructor</span></code></a><span style="">&lt;</span><span style="">?</span><span style="">&gt;</span><span style="">[]</span>&nbsp;<span style="color:#000000;">getDeclaredConstructors</span><span style="">(</span><span style="">)</span>
<span style="color:#000080;font-weight:bold;">public</span>&nbsp;<a href="psi_element://java.lang.reflect.Constructor"><code><span style="color:#000000;">java.<wbr>lang.<wbr>reflect.<wbr>Constructor</span></code></a><span style="">&lt;</span><span style="">?</span><span style="">&gt;</span><span style="">[]</span>&nbsp;<span style="color:#000000;">getDeclaredConstructors</span><span style="">(</span><span style="">)</span>
<span style="color:#000080;font-weight:bold;">throws</span>&nbsp;<a href="psi_element://java.lang.SecurityException"><code><span style="color:#000000;">SecurityException</span></code></a></pre></div><table class='sections'><tr><td valign='top' class='section'><p>Throws:</td><td valign='top'><p><a href="psi_element://java.lang.SecurityException"><code><span style="color:#0000ff;">SecurityException</span></code></a></td></table><div class="bottom"><icon src="AllIcons.Nodes.PpLibFolder"/>&nbsp;&lt; java 10 &gt;</div>

View File

@@ -4,8 +4,8 @@
type, in the order they're declared. This method may be
used to iterate over the constants as follows:
<pre>
for(E c : E.values())
System.out.println(c);
for(E c : E.<wbr>values())
System.<wbr>out.<wbr>println(c);
</pre>
</div><table class='sections'><tr><td valign='top' class='section'><p>Returns:</td><td valign='top'><p>an array containing the constants of this enum type, in the order they're declared</td></table>

View File

@@ -289,7 +289,7 @@ class JavaDocumentationTest : LightJavaCodeInsightFixtureTestCase() {
val actual = JavaExternalDocumentationTest.getDocumentationText(myFixture.project, input)
val expected = "<html><div class='content'>Candidates for method call <b>s.regionMatches()</b> are:<br>" +
val expected = "<html><div class='content'>Candidates for method call <b>s.<wbr>regionMatches()</b> are:<br>" +
"<br>" +
"&nbsp;&nbsp;<a href=\"psi_element://java.lang.String#regionMatches(int, java.lang.String, int, int)\">boolean regionMatches(int, String, int, int)</a><br>" +
"&nbsp;&nbsp;<a href=\"psi_element://java.lang.String#regionMatches(boolean, int, java.lang.String, int, int)\">boolean regionMatches(boolean, int, String, int, int)</a><br>" +
@@ -309,7 +309,7 @@ class JavaDocumentationTest : LightJavaCodeInsightFixtureTestCase() {
val documentationManager = DocumentationManager.getInstance(myFixture.project)
JavaExternalDocumentationTest.getDocumentationText(myFixture.project, input) { component ->
val expected = "<html><div class='content'>Candidates for method call <b>s.regionMatches()</b> are:<br>" +
val expected = "<html><div class='content'>Candidates for method call <b>s.<wbr>regionMatches()</b> are:<br>" +
"<br>" +
"&nbsp;&nbsp;<a href=\"psi_element://java.lang.String#regionMatches(int, java.lang.String, int, int)\">boolean regionMatches(int, String, int, int)</a><br>" +
"&nbsp;&nbsp;<a href=\"psi_element://java.lang.String#regionMatches(boolean, int, java.lang.String, int, int)\">boolean regionMatches(boolean, int, String, int, int)</a><br>" +

View File

@@ -81,10 +81,11 @@ public abstract class DocumentationEditorPane extends JEditorPane implements Dis
}
setBackground(BACKGROUND_COLOR);
HTMLEditorKit editorKit = new HTMLEditorKitBuilder()
.replaceViewFactoryExtensions(DocumentationHtmlUtil.getIconsExtension(iconResolver),
.replaceViewFactoryExtensions(getIconsExtension(iconResolver),
Extensions.BASE64_IMAGES,
Extensions.INLINE_VIEW_EX,
Extensions.FIT_TO_WIDTH_IMAGES)
Extensions.FIT_TO_WIDTH_IMAGES,
Extensions.WBR_SUPPORT)
.withFontResolver(EditorCssFontResolver.getGlobalInstance()).build();
updateDocumentationPaneDefaultCssRules(editorKit);

View File

@@ -16,6 +16,7 @@ import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil
import org.intellij.lang.annotations.Language
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Contract
import java.awt.Color
import java.util.function.Function
import javax.swing.Icon
@@ -79,6 +80,7 @@ object DocumentationHtmlUtil {
val contentSpacing = scale(contentSpacing)
val contentInnerPadding = scale(contentInnerPadding)
@Suppress("CssUnusedSymbol")
@Language("CSS")
val result = ContainerUtil.newLinkedList(
"""
@@ -116,4 +118,115 @@ object DocumentationHtmlUtil {
result.addAll(getDefaultFormattingStyles(contentSpacing))
return result
}
@JvmStatic
@Contract(pure = true)
fun addWordBreaks(text: String): String {
val codePoints = text.codePoints().iterator()
if (!codePoints.hasNext()) return ""
val result = StringBuilder(text.length + 50)
var codePoint = codePoints.nextInt()
val tagName = StringBuilder()
fun next(builder: StringBuilder = result) {
builder.appendCodePoint(codePoint)
codePoint = if (codePoints.hasNext())
codePoints.nextInt()
else
-1
}
while (codePoint >= 0) {
// break after dot if surrounded by letters
when {
Character.isLetter(codePoint) -> {
next()
if (codePoint == '.'.code) {
next()
if (Character.isLetter(codePoint)) {
result.append("<wbr>")
}
}
}
// break after ], ) or / followed by a char or digit
codePoint == ')'.code || codePoint == ']'.code || codePoint == '/'.code -> {
next()
if (Character.isLetterOrDigit(codePoint)) {
result.append("<wbr>")
}
}
// skip tag
codePoint == '<'.code -> {
next()
if (codePoint == '/'.code)
next()
if (!Character.isLetter(codePoint))
continue
tagName.clear()
while (Character.isLetterOrDigit(codePoint) || codePoint == '-'.code) {
next(tagName)
}
result.append(tagName)
if (tagName.contentEquals("style", true)
|| tagName.contentEquals("title", true)
|| tagName.contentEquals("script", true)) {
val curTag = tagName.toString()
do {
if (codePoint == '<'.code) {
next()
if (codePoint == '/'.code) {
next()
tagName.clear()
while (Character.isLetterOrDigit(codePoint) || codePoint == '-'.code) {
next(tagName)
}
result.append(tagName)
if (tagName.contentEquals(curTag, true)) {
while (codePoint >= 0 && codePoint != '>'.code) {
next()
}
break
}
}
}
else next()
}
while (true)
}
else {
while (codePoint >= 0) {
when (codePoint) {
'>'.code -> {
next()
break
}
'\''.code, '"'.code -> {
val quoteStyle = codePoint
next()
while (codePoint >= 0) {
when (codePoint) {
'\\'.code -> {
next()
if (codePoint >= 0)
next()
}
quoteStyle -> {
next()
break
}
else -> next()
}
}
}
else -> next()
}
}
}
}
else -> next()
}
}
return result.toString()
}
}

View File

@@ -112,6 +112,7 @@ import static com.intellij.lang.documentation.DocumentationMarkup.*;
*
* @deprecated Unused in v2 implementation. Unsupported: use at own risk.
*/
@SuppressWarnings("removal")
@Deprecated(forRemoval = true)
public class DocumentationManager extends DockablePopupManager<DocumentationComponent> {
public static final String JAVADOC_LOCATION_AND_SIZE = "javadoc.popup";
@@ -1942,6 +1943,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
//noinspection HardCodedStringLiteral
if (!text.startsWith("<p", nextChar) && !text.startsWith("<div", nextChar)) {
//noinspection HardCodedStringLiteral
text = text.substring(0, nextChar) + "<p>" + text.substring(nextChar);
}
}
@@ -1970,6 +1972,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
//workaround for Swing html renderer not removing empty paragraphs before non-inline tags
text = text.replaceAll("<p>\\s*(<(?:[uo]l|h\\d|p|tr|td))", "$1");
text = addExternalLinksIcon(text);
text = DocumentationHtmlUtil.addWordBreaks(text);
return text;
}

View File

@@ -289,7 +289,6 @@ object QuickDocHighlightingHelper {
"li { padding: ${scale(1)}px 0 ${scale(2)}px 0; }",
"li p { padding-top: 0; padding-bottom: 0; }",
"th { text-align: left; }",
"table { width: 100%}",
"tr, table { margin: 0 0 0 0; padding: 0 0 0 0; }",
"td { margin: 0 0 0 0; padding: 0 0 ${spacing}px 0; }",
"td p { padding-top: 0; padding-bottom: 0; }",

View File

@@ -79,6 +79,8 @@ object StyleSheetRulesProviderForCodeHighlighting {
if (enableInlineCodeBackground) {
val selectors = inlineCodeParentSelectors.asSequence().map { "$it code" }.joinToString(", ")
result.add("$selectors $codeColorStyle")
// 'caption-side' is a hack to support 'border-radius'.
// See also: com.intellij.util.ui.html.InlineViewEx
result.add("$selectors { padding: 1px 4px; margin: 1px 0px; caption-side: 10px; }")
}
if (enableCodeBlocksBackground) {

View File

@@ -6,9 +6,10 @@ import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.util.text.HtmlChunk
import com.intellij.ui.scale.JBUIScale
import com.intellij.util.text.nullize
import com.intellij.util.ui.html.FitToWidthImageView
import com.intellij.util.ui.html.HiDpiScalingImageView
import com.intellij.util.ui.html.InlineViewEx
import com.intellij.util.ui.html.FitToWidthImageView
import com.intellij.util.ui.html.WbrView
import java.awt.*
import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream
@@ -48,7 +49,7 @@ class ExtendableHTMLViewFactory internal constructor(
companion object {
@JvmField
val DEFAULT_EXTENSIONS: List<Extension> = listOf(Extensions.ICONS, Extensions.BASE64_IMAGES, Extensions.HIDPI_IMAGES,
Extensions.INLINE_VIEW_EX)
Extensions.INLINE_VIEW_EX, Extensions.WBR_SUPPORT)
@JvmField
val DEFAULT: ExtendableHTMLViewFactory = ExtendableHTMLViewFactory(DEFAULT_EXTENSIONS)
@@ -134,6 +135,12 @@ class ExtendableHTMLViewFactory internal constructor(
@JvmField
val FIT_TO_WIDTH_IMAGES: Extension = FitToWidthImageViewExtension()
/**
* Adds support for `<wbr>` tags
*/
@JvmField
val WBR_SUPPORT: Extension = WbrSupportExtension()
private class IconsExtension(private val existingIconsProvider: (key: String) -> Icon?) : Extension {
constructor(preloadedIcons: Map<String, Icon>) : this(preloadedIconsProvider(preloadedIcons))
@@ -361,7 +368,7 @@ class ExtendableHTMLViewFactory internal constructor(
}
}
private class InlineViewExExtension: Extension {
private class InlineViewExExtension : Extension {
override fun invoke(element: Element, view: View): View? {
if (view.javaClass != InlineView::class.java) return null
val attrs = view.attributes
@@ -381,10 +388,18 @@ class ExtendableHTMLViewFactory internal constructor(
}
}
private class FitToWidthImageViewExtension: Extension {
private class FitToWidthImageViewExtension : Extension {
override fun invoke(element: Element, view: View): View? =
if (view is ImageView) FitToWidthImageView(element) else null
}
private class WbrSupportExtension : Extension {
override fun invoke(elem: Element, defaultView: View): View? =
if (elem.name.equals("wbr", true))
WbrView(elem)
else
null
}
}
private class HiDpiImagesExtension : ExtendableHTMLViewFactory.Extension {

View File

@@ -46,20 +46,6 @@ internal class InlineViewEx(elem: Element) : InlineView(elem) {
override fun setPropertiesFromAttributes() {
super.setPropertiesFromAttributes()
val parentView = parent
val index = (0..parentView.viewCount).firstOrNull { parentView.getView(it) === this } ?: -1
// Heuristics to determine whether we are within the same inline (e.g. <span>) element with paddings.
// Nested inline element insets are not supported, because hierarchy of inline elements is not preserved.
val prevSibling = if (index > 0) parentView.getView(index - 1) else null
val nextSibling = if (index < parentView.viewCount - 1) parentView.getView(index + 1) else null
padding = this.cssPadding
margin = this.cssMargin
startView = prevSibling?.cssPadding != padding || prevSibling.cssMargin != margin
endView = nextSibling?.cssPadding != padding || nextSibling.cssMargin != margin
// "caption-side" is used as "border-radius"
borderRadius = attributes.getAttribute(CAPTION_SIDE)
@@ -69,27 +55,7 @@ internal class InlineViewEx(elem: Element) : InlineView(elem) {
?.toIntOrNull()
?.let { JBUI.scale(it) }
?: 0
padding.set(
padding.top,
if (startView) padding.left else 0,
padding.bottom,
if (endView) padding.right else 0,
)
margin.set(
margin.top,
if (startView) margin.left else 0,
margin.bottom,
if (endView) margin.right else 0,
)
insets = JBInsets(
padding.top + margin.top,
padding.left + margin.left,
padding.bottom + margin.bottom,
padding.right + margin.right,
)
updatePaddingsAndMargins(true)
}
override fun getPartialSpan(p0: Int, p1: Int): Float {
@@ -103,12 +69,14 @@ internal class InlineViewEx(elem: Element) : InlineView(elem) {
return offset + super.getPartialSpan(p0, p1)
}
override fun getPreferredSpan(axis: Int): Float =
super.getPreferredSpan(axis) + when (axis) {
override fun getPreferredSpan(axis: Int): Float {
updatePaddingsAndMargins(false)
return super.getPreferredSpan(axis) + when (axis) {
View.X_AXIS -> insets.width()
View.Y_AXIS -> insets.height()
else -> throw IllegalArgumentException("Invalid axis: $axis")
}
}
override fun getTabbedSpan(x: Float, e: TabExpander?): Float =
super.getTabbedSpan(x, e) + insets.width()
@@ -173,4 +141,59 @@ internal class InlineViewEx(elem: Element) : InlineView(elem) {
return super.getAlignment(axis)
}
private fun getSibling(parentView: View, curIndex: Int, direction: Int): View? {
var siblingIndex = curIndex + direction
val viewCount = parentView.viewCount
while (siblingIndex in 0..<viewCount) {
parentView.getView(siblingIndex)
.takeIf { it.element?.name?.equals("wbr", true) != true }
?.let { return it }
siblingIndex += direction
}
return null
}
private fun updatePaddingsAndMargins(force: Boolean) {
val parentView = parent
val index = (0..<parentView.viewCount).firstOrNull { parentView.getView(it) === this } ?: -1
// Heuristics to determine whether we are within the same inline (e.g. <span>) element with paddings.
// Nested inline element insets are not supported, because hierarchy of inline elements is not preserved.
val prevSibling = getSibling(parentView, index, -1)
val nextSibling = getSibling(parentView, index, 1)
val cssPadding = this.cssPadding
val cssMargin = this.cssMargin
val startView = prevSibling?.cssPadding != cssPadding || prevSibling.cssMargin != cssMargin
val endView = nextSibling?.cssPadding != cssPadding || nextSibling.cssMargin != cssMargin
if (!force && startView == this.startView && endView == this.endView) {
return
}
this.startView = startView
this.endView = endView
padding = JBInsets(
cssPadding.top,
if (startView) cssPadding.left else 0,
cssPadding.bottom,
if (endView) cssPadding.right else 0,
)
margin = JBInsets(
cssMargin.top,
if (startView) cssMargin.left else 0,
cssMargin.bottom,
if (endView) cssMargin.right else 0,
)
insets = JBInsets(
padding.top + margin.top,
padding.left + margin.left,
padding.bottom + margin.bottom,
padding.right + margin.right,
)
}
}

View File

@@ -0,0 +1,38 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.ui.html
import java.awt.Shape
import javax.swing.text.Element
import javax.swing.text.Position
import javax.swing.text.Segment
import javax.swing.text.View
import javax.swing.text.html.InlineView
class WbrView(elem: Element) : InlineView(elem) {
override fun getMinimumSpan(axis: Int): Float = 0f
override fun getMaximumSpan(axis: Int): Float =
if (axis == View.X_AXIS)
0f
else
Int.MAX_VALUE.toFloat()
override fun getViewIndex(pos: Int, b: Position.Bias?): Int = -1
override fun getViewIndex(x: Float, y: Float, allocation: Shape?): Int = -1
override fun getResizeWeight(axis: Int): Int = 0
override fun setSize(width: Float, height: Float) {
super.setSize(0f, 0f)
}
override fun getPreferredSpan(axis: Int): Float = 0f
override fun getText(p0: Int, p1: Int): Segment = Segment()
override fun breakView(axis: Int, offset: Int, pos: Float, len: Float): View = this
override fun getBreakWeight(axis: Int, pos: Float, len: Float): Int = ExcellentBreakWeight
}