Skip to content
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

Why is a CoreGraphics version of System.Drawing needed #24

Open
joyinfo opened this issue Jul 25, 2019 · 10 comments
Open

Why is a CoreGraphics version of System.Drawing needed #24

joyinfo opened this issue Jul 25, 2019 · 10 comments

Comments

@joyinfo
Copy link

joyinfo commented Jul 25, 2019

To use the Cocoa driver for System.Windows.Forms, isn't writing and using a XplatUICocoa in System.Windows.Forms enough? Why is a CoreGraphics version of System.Drawing introduced?

Thanks

@filipnavara
Copy link
Collaborator

filipnavara commented Jul 26, 2019

We originally started with the Mono's System.Drawing implementation. There are fundamental problems with it:

  • This implementation relies on several native libraries underneath, directly on indirectly (libgdiplus, Cario, FreeType, fontconfig, etc.). At that time it was not very actively maintained and it was quite buggy too. In addition to that, on first run on macOS fontconfig has to build a cache that may take almost half a minute when the application appears unresponsive.
  • We cannot use the library as is because we need to draw into NSView Cocoa objects. We use single NSView for each Control much like Windows does. The Controls in Windows are, however, devided into client and non-client (border, window caption) parts. The public API of System.Drawing should present you only the non-client part. That requires some cooperation with the implementation in XplatUICocoa. Similarly, System.Windows.Forms also needs an ability to get Graphics object representing the non-client area. This is not covered by the public API surface of System.Drawing and needs some cooperation too. On Windows there are constructors that take HDC objects but that is not portable to other systems unless both libraries (System.Windows.Forms and System.Drawing) agree on the meaning of the HDC and use it the same way. That is tricky when garbage collection takes place and you only have IntPtr to pass around.
  • Mono's System.Drawing and libgdiplus didn't work in 64-bit processes, at all.
  • libgdiplus font drawing didn't look "native".

Faced with these challenges we decided to go with the Cocoa implementation of System.Drawing instead. It is siginificantly faster for our purposes and makes interoperability with the native controls much easier. It also allowed us to add dark mode support recently by directly mapping Color and NSColor objects representing system colors.

That said, I spent almost a year fixing bugs in libgdiplus and Mono's System.Drawing. It now runs on 64-bit, can render internation fonts with Pango (which can use native Cocoa rendering) and most of the fundamental bugs are fixed. Last year I tried to port the XplatUICocoa back to run with Mono's System.Windows.Forms+System.Drawing. I had something up and running in a day and it mostly worked but it was nowhere near as polished as the implementation in this repository, and it lacks the native controls.

@joyinfo
Copy link
Author

joyinfo commented Jul 26, 2019

Thanks very much for your answer. I think you did great work.

I have some more questions.

  1. Do you mean you made a libgdiplus and Mono's System.Drawing which can run on 64-bit on macOS? Did you ever publish them on github?
  2. The implementation in this repository does not longer need libgdiplus, right?
  3. Does the XplatUICocoa in this implementation invoke Cocoa API directly, or through the Cocoa version of System.Drawing?

@filipnavara
Copy link
Collaborator

Do you mean you made a libgdiplus and Mono's System.Drawing which can run on 64-bit? Did you ever publish them on github?

It is upstreamed in Mono at this point. I believe it should be part of the stable Mono 6.0 release.

The implementation in this repository does not longer need libgdiplus, right?

Correct

Does the XplatUICocoa in this implementation invoke Cocoa API directly, or through the Cocoa version of System.Drawing?

Both. It need the Cocoa API for creating windows, all drawing is done through System.Drawing.

@joyinfo
Copy link
Author

joyinfo commented Jul 26, 2019

I think the current libgdiplus invokes Carbon API, am I right?, which only supports 32-bit. So in the coming Mono 6.0 release, will the libgdiplus shift from Carbon to Cocoa?

@filipnavara
Copy link
Collaborator

It supports both Carbon and Cocoa. The Carbon code is 32-bit only. The Cocoa code is there to support integration with apps written in Xamarin.Mac and it has to be specifically enabled through some API call.

@joyinfo
Copy link
Author

joyinfo commented Jul 28, 2019

Thanks.

@joyinfo
Copy link
Author

joyinfo commented Aug 28, 2019

I downloaded the source code of Mono-6.4.0.181 and found no way to set GDIPlus.UseCocoaDrawable be true. Is there API available to use Cocoa in Mono-6.4.0?

@filipnavara
Copy link
Collaborator

There is no public API except the one in Xamarin.Mac listed above which uses reflection to set GDIPlus.UseCocoaDrawable.

@joyinfo
Copy link
Author

joyinfo commented Aug 28, 2019

In line 123 of mcs/class/System.Drawing/System.Drawing/gdipFunctions.cs, I set UseCocoaDrawable be true rather than UseCarbonDrawable and built the Mono-6.4.0.181 runtime in my mac and built / ran my application with the new runtime, there are same visibility and z-order issues. I did not see anything improved.

			if (os == "Darwin")
				UseCocoaDrawable = true;
			else
				UseX11Drawable = true;

Does this work to use Cocoa? If not, can you give me some code to use reflection to set GDIPlus.UseCocoaDrawable?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants