-
Notifications
You must be signed in to change notification settings - Fork 190
Using ImageHandleManager for managing multiple Image handles in Image class #2927
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Using ImageHandleManager for managing multiple Image handles in Image class #2927
Conversation
HeikoKlare
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look like a good refactoring to better encapsulate the management of handles for zooms and in general are fine fore me. I still have some proposals for improvements.
bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
Outdated
Show resolved
Hide resolved
bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
Show resolved
Hide resolved
bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
Outdated
Show resolved
Hide resolved
|
|
||
| public void destroy() { | ||
| if (handleContainer != null && !zoomLevelToImageHandle.containsValue(handleContainer)) { | ||
| if (handleContainer != null && !imageHandleManager.hasImageHandle(handleContainer)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hasImageHandle method is only used here and rather indicates a missing local state handling, I would propose to remove that method and manage the state locally instead.
The method is used to find out, if this HandleAtSize has created the handle on its own or whether it was retrieved from the ImageHandleManager. So the HandleAtSize could just store that it created the handle on its own (inside refresh()) and then just use that information here to determine if the handleContainer needs to be destroyed or not instead of indirectly retrieving that information again by querying the ImageHandleManager for whether it contains that handle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. As I can see, HandleAtSize doesn't register any ImageHandle explicitly and init is called with -1, which from the previous convention also means that it wasn't event intended to be added to the map. And as I can see, it is never added in the ImageHandleManager with the current implementation so I would simply remove this check as it is always true. And I will get rid of the method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct. The handleContainer may be a handle from the ImageHandleManager, as refresh() may call getOrCreateImageHandleAtClosestSize(width, height) which can retrieve a handle from there. So it is not guaranteed that this handle is locally managed. The latest change may lead to a handle inside the ImageHandleManager being disposed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should add a check somewhere to better find accidental changes to the implementation that destroys handles from the manager outside of it? E.g., ImageHandle#destroy() may check for the handle not being contained in the ImageHandleManager.
Or may we can even better do that in an OO-safe way: remove the destroy method from ImageHandle and create a DestroyableImageHandle or the like. Then ImageHandleManager could only expose ImageHandle instances while internally managing destroyable ones. And the places where handles are created locally would maintain destroyable instances as well. Since we pass ImageHandles over to GC as well that would even increase safety as those other code places not not accidentally destroy handles anymore as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although with this approach here we still need to check if it is in the manager because either we obtain it from the manager (Exposed Imagehandle) or create a temporary (DestroyableImageHandle)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also the method which creates ImageHandle is consumed by both temporary user and permanent user, so we can utilize factory pattern here to create the instance of a specific class depending on who the consumer is.
Then we can have the following:
- ImageHandle (no destroy, created by imageHandleManager, destroyed by a specific method inside the manager)
- TemporaryHandle extends ImageHandle, has a destroy method.
- we can check if the instance is a temporaryhandle then destroy, in the case above. If type already know, destroying is straight forward.
| private void initWithImageHandle(Drawable drawable, GCData data, long hDC, ImageHandle imageHandle) { | ||
| Image image = data.image; | ||
| data.image = null; | ||
| init(drawable, data, hDC); | ||
| data.hNullBitmap = OS.SelectObject(hDC, imageHandle.getHandle()); | ||
| image.memGC = this; | ||
| data.image = image; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are all these changes to GC necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- PlainImageProviderWrapper#newImageHandle needs to perform
GC#initamidst the creation ofImageHandleusingImageHandleManager#getOrCreatewhich is a synchronous call. GC#initcallsImage.win32_getHandlewhich tries to create the handle since the current ImageHandle is not added to the map yet. As getOrCreate at first waits for the operation to complete and return a handle and then adds it to the map. We could provide a method likeregister(ImageHandle)which adds the ImageHandle amidst the creation of the ImageHandle using this method but then we put the manager at risk that some other consumer inside Image can misuse it. And what if newImageHandle (where the ImageHandle creation takes place) is called by some other consumer? Then the guarantee of synchronous ImageHandle creation will be lost.- Hence, this takes a ImageHandle instead of the Image and perform the operation using the handle and not Image object.
83421c0 to
3136fc1
Compare
This commit adds a class ImageHandleManager in Image to manage multiple ImageHandle for different zoom hence encapsulating the usages and operations based on zoomLevelToImageHandle.
3136fc1 to
fec96c6
Compare
This PR introduces ImageHandleManager, an inner class to Image responsible for managing the storage, creation and manipulation of ImageHandles. This class provides methods which can be used to dead with ImageHandle instances inside an image for managing it with convenience while hiding the complexity of how the ImageHandle lifecycle is managed inside itself.
All the places where zoomToImageHandle map is accessed for any purposes is replaced by the wrapper methods provided by ImageHandleManager. Each image initializes a final field imageHandleManager with the instance of ImageHandleManager. Every instance of ImageHandle created within the Image object which is meant to be stored per zoom is registered in the manager itself and the manager is responsible for cleaning the dangling resources when are not supposed to be used anymore or when a cleanup is needed.
This contributes to vi-eclipse/Eclipse-Platform#562