In this post we will discuss the steps towards merging two seemingly distinct concepts in Pharo into a single class, namely TranslucentColor and Color, given that the latter can suffice for modelling instances of the former. A color instance instance can either opaque or translucent, while preserving it’s rgb component intact.
About the direct references to the class
Currently, there are 9 users of TranslucentColor in the image (version 3.0, update #30375).
- Color>>alpha: alphaValue
- Color class>>fromArray: colorDef
- Paragraph class>>insertionPointColor
The enumerated methods directly reference the TranslucentColor class, but should use the class method #r:g:b:alpha: instead .
Modifying the 9 users of TranslucentColor methods in a similar manner, enables us to remove every direct uses of TranslucentColor, but this is not enough for simply discarding the redundant class, we have to refactor Color into modeling both opaque and translucent colors.
The method #isTranslucentColor appears to be another direct reference to the unwanted class, although the name is misleading because both implementors (Color and TranslucentColor) specify wether the instance is translucent but not transparent.
We decided to rename #hasTranslucentColor to #isTranslucentButNotTransparent, for having an explicit name that better describes the intention of the method.
About moving up ‘alpha’ to Color
To accomplish our goal of removing the redundant class for modelling translucent colors, we have to move both the instance variable named ‘alpha’ (which specifies the amount of translucency), and the methods that refer to it from TranslucentColor to Color.
The resulting Color should be the following:
First, we modified all the instance creation methods for creating new instances of opaque and translucent colors. Since we were already cleaning up Color, I decided to rename the initialization methods from #setRed:green:blue and #setRed:green:blue:range, to #initializeRed:green:blue:, compliant with modern Pharo idioms.
Second, we moved up all the queries related to translucency: #isTranslucent, #isTransparent, and #isTranslucentButNotTransparent. Then, we added the ‘alpha’ component to the #hash and #= methods.
To conclude our refactoring to move up the ‘alpha’ instance variable, we had to modify several conversion methods in the Color class, such as #+, #-, #/, and other Form related methods such as #basicPixelValueForDepth:, #pixelValueForDepth:, and #scaledPixelValue32, to make them consider the translucency of the color.
To discard the redundant class, we have to prepare the image by migrating all instances of TranslucentColor to a simple Color instance with the correct alpha component. The following code performs the final removal:
About performing the refactoring
Similarly to any class belonging to the graphics kernel, modifying Color and removing TranslucentColor is hazardous, because one attempts to change the behavior of color instances used by the very same tools of the IDE who heavily rely on them.
So the best approach is to programatically perform all the changes, and cleanups in a transactional manner, thus I designed a TranslucentColorRemoval class, that:
- move alpha from TranslucentColor to Color.
- carefully initialises all sub-instances of Color to the correct alpha values.
- loads the change-sets including the complete refactoring.
- migrates all remaining instances of TranslucentColor to Color using #become.
- and finally removes the redundant class!
To load the refactoring, evaluate the following method:
I’ve submitted the code to Issue 11519 in the Pharo bug tracker
There you can find the change set of the refactoring, and the importer class.
At RMoD, we’ve been working on the rendering, view and morphic layer of the new text model, with the aim of replacing entirely the one in use, based on Paragraph, TextEditor, and TextMorph and friends. In the next post I will introduce the work and present the first demo’s.