fix icon cache - avoid wrapping, avoid not needed scale context update as a part of cache lookup (CachedImageIcon is responsible for that and does it perfectly)

GitOrigin-RevId: 02758f152b6fb7ce3d6b2e5fbe7d7e2af50ee01f
This commit is contained in:
Vladimir Krivosheev
2023-03-13 11:11:41 +00:00
committed by intellij-monorepo-bot
parent c82f50d8df
commit 86b840652f
3 changed files with 53 additions and 42 deletions
@@ -623,33 +623,24 @@ fun findIconUsingDeprecatedImplementation(originalPath: String,
var effectiveClassLoader = classLoader
val startTime = StartUpMeasurer.getCurrentTimeIfEnabled()
val patchedPath = CachedImageIcon.patchPath(originalPath = originalPath, classLoader = effectiveClassLoader)
val path = patchedPath?.first ?: originalPath
val effectivePath = patchedPath?.first ?: originalPath
if (patchedPath?.second != null) {
effectiveClassLoader = patchedPath.second
}
val icon: Icon?
if (isReflectivePath(path)) {
icon = getReflectiveIcon(path = path, classLoader = effectiveClassLoader)
var icon: Icon?
if (isReflectivePath(effectivePath)) {
icon = getReflectiveIcon(path = effectivePath, classLoader = effectiveClassLoader)
}
else {
val key = Pair(originalPath, effectiveClassLoader)
var cachedIcon = iconCache.getIfPresent(key)
if (cachedIcon == null) {
cachedIcon = iconCache.get(key) { k ->
val resolver = ImageDataByPathResourceLoader(path = path, ownerClass = aClass, classLoader = k.second, strict = strict)
CachedImageIcon(originalPath = originalPath, resolver = resolver, toolTip = toolTip)
icon = iconCache.getIfPresent(key)
if (icon == null) {
icon = iconCache.get(key) { k ->
val resolver = ImageDataByPathResourceLoader(path = effectivePath, ownerClass = aClass, classLoader = k.second, strict = strict)
CachedImageIcon(originalPath = k.first, resolver = resolver, toolTip = toolTip)
}
}
else {
val scaleContext = ScaleContext.create()
if (cachedIcon.scaleContext != scaleContext) {
// honor scale context as 'iconCache' doesn't do that
cachedIcon = cachedIcon.copy()
cachedIcon.updateScaleContext(scaleContext)
}
}
icon = cachedIcon
}
if (startTime != -1L) {
IconLoadMeasurer.findIcon.end(startTime)
@@ -8,9 +8,7 @@ import com.intellij.openapi.util.IconPathPatcher
import com.intellij.openapi.util.ScalableIcon
import com.intellij.openapi.util.SystemInfoRt
import com.intellij.reference.SoftReference
import com.intellij.ui.scale.AbstractScaleContextAware
import com.intellij.ui.scale.ScaleContext
import com.intellij.ui.scale.ScaleType
import com.intellij.ui.scale.*
import com.intellij.util.SVGLoader
import com.intellij.util.containers.CollectionFactory
import com.intellij.util.ui.MultiResolutionImageProvider
@@ -39,8 +37,8 @@ open class CachedImageIcon protected constructor(
private val colorPatcher: SVGLoader.SvgElementColorPatcherProvider? = null,
private val useStroke: Boolean = false,
private val toolTip: Supplier<String?>? = null,
) : AbstractScaleContextAware<ScaleContext>(ScaleContext.create()), CopyableIcon, ScalableIcon, DarkIconProvider, MenuBarIconProvider,
IconWithToolTip {
private val scaleContext: ScaleContext = ScaleContext.create(),
) : CopyableIcon, ScalableIcon, DarkIconProvider, MenuBarIconProvider, IconWithToolTip, ScaleContextAware {
companion object {
@JvmField
internal var isActivated: Boolean = !GraphicsEnvironment.isHeadless()
@@ -101,22 +99,32 @@ open class CachedImageIcon protected constructor(
}
}
final override fun getScaleContext(): ScaleContext = scaleContext
final override fun updateScaleContext(ctx: UserScaleContext?): Boolean = scaleContext.update(ctx)
final override fun getScale(type: ScaleType): Double = scaleContext.getScale(type)
final override fun getScale(type: DerivedScaleType): Double = scaleContext.getScale(type)
final override fun setScale(scale: Scale): Boolean = scaleContext.setScale(scale)
override fun getToolTip(composite: Boolean): String? = toolTip?.get()
override fun paintIcon(c: Component?, g: Graphics, x: Int, y: Int) {
getRealIcon(ScaleContext.create(if (g is Graphics2D) g else null)).paintIcon(c, g, x, y)
final override fun paintIcon(c: Component?, g: Graphics, x: Int, y: Int) {
getRealIcon(scaleContext = null, sysScale = JBUIScale.sysScale(g as? Graphics2D?).toDouble()).paintIcon(c, g, x, y)
}
override fun getIconWidth(): Int = getRealIcon(scaleContext = null).iconWidth
final override fun getIconWidth(): Int = getRealIcon(scaleContext = null).iconWidth
override fun getIconHeight(): Int = getRealIcon(scaleContext = null).iconHeight
final override fun getIconHeight(): Int = getRealIcon(scaleContext = null).iconHeight
override fun getScale(): Float = 1.0f
final override fun getScale(): Float = 1.0f
@ApiStatus.Internal
fun getRealIcon(): ImageIcon = getRealIcon(scaleContext = null)
internal fun getRealIcon(scaleContext: ScaleContext?): ImageIcon {
internal fun getRealIcon(scaleContext: ScaleContext?, sysScale: Double = -1.0): ImageIcon {
if (resolver == null || !isActivated) {
return EMPTY_ICON
}
@@ -147,14 +155,22 @@ open class CachedImageIcon protected constructor(
}
synchronized(lock) {
val updated = if (sysScale == -1.0) {
this.scaleContext.update(scaleContext)
}
else {
assert(scaleContext == null)
this.scaleContext.setScale(ScaleType.SYS_SCALE.of(sysScale))
}
// try returning the current icon as the context is up-to-date
if (!updateScaleContext(scaleContext) && realIcon != null) {
if (!updated && realIcon != null) {
unwrapIcon(realIcon)?.let {
return it
}
}
scaledIconCache.getOrScaleIcon(scale = 1.0f, host = this, scaleContext = this.scaleContext)?.let { icon ->
val icon = scaledIconCache.getOrScaleIcon(scale = 1.0f, host = this, scaleContext = this.scaleContext)
if (icon != null) {
this.realIcon = if (icon.iconWidth < 50 && icon.iconHeight < 50) icon else SoftReference(icon)
return icon
}
@@ -1,4 +1,6 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("LiftReturnOrAssignment")
package com.intellij.ui.scale
import com.intellij.diagnostic.runActivity
@@ -25,7 +27,7 @@ import kotlin.math.roundToInt
object JBUIScale {
@JvmField
@Internal
val SCALE_VERBOSE = java.lang.Boolean.getBoolean("ide.ui.scale.verbose")
val SCALE_VERBOSE: Boolean = java.lang.Boolean.getBoolean("ide.ui.scale.verbose")
private const val USER_SCALE_FACTOR_PROPERTY = "JBUIScale.userScaleFactor"
@@ -87,7 +89,7 @@ object JBUIScale {
// with JB Linux JDK the label font comes properly scaled based on Xft.dpi settings.
var font: Font
if (SystemInfoRt.isMac) {
// see AquaFonts.getControlTextFont() - lucida13Pt is hardcoded
// see AquaFonts.getControlTextFont() - lucida13Pt is a hardcoded
// text family should be used for relatively small sizes (<20pt), don't change to Display
// see more about SF https://medium.com/@mach/the-secret-of-san-francisco-fonts-4b5295d9a745#.2ndr50z2v
font = Font(".SF NS Text", Font.PLAIN, 13)
@@ -115,14 +117,14 @@ object JBUIScale {
var dpi = value / 1024
if (dpi < 50) dpi = 50
val scale = if (JreHiDpiUtil.isJreHiDPIEnabled()) 1f else discreteScale(dpi / 96f) // no scaling in JRE-HiDPI mode
// derive actual system base font size
// derive the actual system base font size
DEF_SYSTEM_FONT_SIZE = font.size / scale
if (isScaleVerbose) {
log.info(String.format("DEF_SYSTEM_FONT_SIZE: %.2f", DEF_SYSTEM_FONT_SIZE))
}
}
else if (!SystemInfo.isJetBrainsJvm) {
// With Oracle JDK: derive scale from X server DPI, do not change DEF_SYSTEM_FONT_SIZE
// With Oracle JDK: derive a scale from X server DPI, do not change DEF_SYSTEM_FONT_SIZE
val size = DEF_SYSTEM_FONT_SIZE * screenScale
font = font.deriveFont(size)
if (isScaleVerbose) {
@@ -225,7 +227,8 @@ object JBUIScale {
/**
* Sets the user scale factor.
* The method is used by the IDE, it's not recommended to call the method directly from the client code.
* The IDE uses the method.
* It's not recommended to call the method directly from the client code.
* For debugging purposes, the following JVM system property can be used:
* ide.ui.scale=float
* or the IDE registry keys (for backward compatibility):
@@ -262,14 +265,14 @@ object JBUIScale {
scale = discreteScale(scale)
// downgrading user scale below 1.0 may be uncomfortable (tiny icons),
// whereas some users prefer font size slightly below normal which is ok
// whereas some users prefer font size slightly below normal, which is ok
if (scale < 1 && systemScaleFactor.value >= 1) {
scale = 1f
}
// ignore the correction when UIUtil.DEF_SYSTEM_FONT_SIZE is overridden, see UIUtil.initSystemFontData
if (SystemInfoRt.isLinux && scale == 1.25f && DEF_SYSTEM_FONT_SIZE == 12f) {
// Default UI font size for Unity and Gnome is 15. Scaling factor 1.25f works badly on Linux.
// The default UI font size for Unity and Gnome is 15. Scaling factor 1.25f works badly on Linux.
return 1f
}
else {
@@ -396,11 +399,11 @@ object JBUIScale {
val gc = g.deviceConfiguration
if (gc == null || gc.device.type == GraphicsDevice.TYPE_IMAGE_BUFFER || gc.device.type == GraphicsDevice.TYPE_PRINTER) {
// in this case gc doesn't provide a valid scale
// in this case, gc doesn't provide a valid scale
return abs(g.transform.scaleX.toFloat())
}
else {
return sysScale(gc)
return gc.defaultTransform.scaleX.toFloat()
}
}
@@ -414,8 +417,9 @@ object JBUIScale {
*/
@JvmStatic
fun isHiDPI(scale: Double): Boolean {
// Scale below 1.0 is impractical, it's rather accepted for debug purpose.
// Treat it as "hidpi" to correctly manage images which have different user and real size
// The scale below 1.0 is impractical.
// It's rather accepted for debug purpose.
// Treat it as "hidpi" to correctly manage images which have different users and real size
// (for scale below 1.0 the real size will be smaller).
return scale != 1.0
}