Bug 26425 - Small Refactoring to Consolidate Common GDI Calls
Summary: Small Refactoring to Consolidate Common GDI Calls
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit Misc. (show other bugs)
Version: 528+ (Nightly build)
Hardware: PC Windows XP
: P2 Normal
Assignee: Brent Fulgham
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-15 17:26 PDT by Brent Fulgham
Modified: 2009-06-18 20:49 PDT (History)
2 users (show)

See Also:


Attachments
Rev 1. (15.40 KB, patch)
2009-06-15 17:35 PDT, Brent Fulgham
eric: review-
Details | Formatted Diff | Diff
Rev. 2. (19.92 KB, patch)
2009-06-15 18:12 PDT, Brent Fulgham
no flags Details | Formatted Diff | Diff
Rev 3 (31.38 KB, patch)
2009-06-17 15:39 PDT, Brent Fulgham
aroben: review-
Details | Formatted Diff | Diff
Part 1 (XFORM operator) (3.89 KB, patch)
2009-06-17 16:04 PDT, Brent Fulgham
aroben: review-
Details | Formatted Diff | Diff
Part 2: (BitmapInfo structure) (5.84 KB, patch)
2009-06-17 16:14 PDT, Brent Fulgham
aroben: review-
Details | Formatted Diff | Diff
Part 3: (Use BitmapInfo Structure) (9.64 KB, patch)
2009-06-17 16:35 PDT, Brent Fulgham
no flags Details | Formatted Diff | Diff
Part 1: BitmapInfo Refactoring (14.89 KB, patch)
2009-06-17 16:41 PDT, Brent Fulgham
aroben: review+
Details | Formatted Diff | Diff
Part 2: (Refactor XFORM) (9.46 KB, patch)
2009-06-17 16:56 PDT, Brent Fulgham
aroben: review+
Details | Formatted Diff | Diff
Part 3: (Move common logic to parent) (10.62 KB, patch)
2009-06-17 21:19 PDT, Brent Fulgham
eric: review+
Details | Formatted Diff | Diff
Part 4: (Final cleanups) (6.18 KB, patch)
2009-06-18 14:07 PDT, Brent Fulgham
eric: review+
Details | Formatted Diff | Diff
Part 5: (Some missed cleanups) (7.53 KB, patch)
2009-06-18 17:31 PDT, Brent Fulgham
levin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Brent Fulgham 2009-06-15 17:26:11 PDT
There are a number of places where BITMAPINFO structures and XFORM structures are created.  These are almost always the same, and seem like a good opportunity to abstract these structure filling routines to be shared between the various Windows ports.

This patch adds a new GDIUtilities.h/GDIUtilities.cpp file that contains implementations of routines to:
1.  Construct the typical BITMAPINFO structure we use in various operations.
2.  Clear the data in a BITMAP structure.
3.  Construct a Windows XFORM object from the input matrix components.

After this patch, several methods in GraphicsContextCGWin and GraphicsContextCairoWin can be pushed up to GraphicsContextWin.
Comment 1 Brent Fulgham 2009-06-15 17:35:21 PDT
Created attachment 31320 [details]
Rev 1.
Comment 2 Eric Seidel (no email) 2009-06-15 17:38:03 PDT
Looks great to me.  The patch is missing the new files, and Adam and Steve are the people you should really ask about windows changes.
Comment 3 Eric Seidel (no email) 2009-06-15 17:38:19 PDT
Comment on attachment 31320 [details]
Rev 1.

Missing the added files.
Comment 4 Brent Fulgham 2009-06-15 18:12:59 PDT
Created attachment 31325 [details]
Rev. 2.

Show missing (new) files.
Comment 5 Adam Roben (:aroben) 2009-06-16 10:42:32 PDT
Comment on attachment 31325 [details]
Rev. 2.

> + #ifndef GdiUtilities_h

This should be GDIUtilities_h. We always match the case of the file name.

In general we've tried to resist adding *Utilities files, partly because they can become a catch-all. So I've been trying to think about how we could remove the need for such a file here.

> + XFORM makeXFORM(float, float, float, float, float, float);

I think it would be better to add an operator XFORM() to the TransformationMatrix class instead of adding the makeXFORM function. Then we can change the existing code to use TransformationMatrix::translate to convert the rect into a matrix, and convert that to an XFORM. Does that make sense?

> + BITMAPINFO bitmapInfoForSize(const IntSize&, bool invertHeight = false);

Boolean parameters make it hard to read code, and optional boolean parameters make it really easy to make mistakes when the function signature changes. You could replace the optional boolean with a required two-member enum, like this:

enum BitmapOrientation { TopDown, BottomUp };
BITMAPINFO bitmapInfoForSize(const IntSize&, BitmapOrientation).

Or you could just require the caller to negate the height themselves.

Another option, which would allow moving this function out of GDIUtilities (and get us a step closer to removing that file altogether), would be to create a WebCore::BitmapInfo struct that derives from BITMAPINFO. Something like:

struct BitmapInfo : public BITMAPINFO {
    static BitmapInfo create(const IntSize&);
    static BitmapInfo createBottomUp(const IntSize&);
};

> + void fillWithClearColor(HBITMAP);

I'm not sure what to do with this one.
Comment 6 Brent Fulgham 2009-06-16 11:50:48 PDT
(In reply to comment #5)
> In general we've tried to resist adding *Utilities files, partly because they
> can become a catch-all. So I've been trying to think about how we could remove
> the need for such a file here.

Okay
 
> > + XFORM makeXFORM(float, float, float, float, float, float);
> 
> I think it would be better to add an operator XFORM() to the
> TransformationMatrix class instead of adding the makeXFORM function. Then we
> can change the existing code to use TransformationMatrix::translate to convert
> the rect into a matrix, and convert that to an XFORM. Does that make sense?

Yes.  I can do that.
 
> > + BITMAPINFO bitmapInfoForSize(const IntSize&, bool invertHeight = false);
> Another option, which would allow moving this function out of GDIUtilities (and
> get us a step closer to removing that file altogether), would be to create a
> WebCore::BitmapInfo struct that derives from BITMAPINFO. Something like:
> 
> struct BitmapInfo : public BITMAPINFO {
>     static BitmapInfo create(const IntSize&);
>     static BitmapInfo createBottomUp(const IntSize&);
> };

That's a good idea.  Should this be in its own set of files, or is there someplace  else where this would make sense?
 
> > + void fillWithClearColor(HBITMAP);
> 
> I'm not sure what to do with this one.

The only thing that uses this is GraphicsContextWinXXXX, so I can just make it a method of the class and put it there.
Comment 7 Adam Roben (:aroben) 2009-06-16 14:43:57 PDT
(In reply to comment #6)
> (In reply to comment #5)
> > > + BITMAPINFO bitmapInfoForSize(const IntSize&, bool invertHeight = false);
> > Another option, which would allow moving this function out of GDIUtilities (and
> > get us a step closer to removing that file altogether), would be to create a
> > WebCore::BitmapInfo struct that derives from BITMAPINFO. Something like:
> > 
> > struct BitmapInfo : public BITMAPINFO {
> >     static BitmapInfo create(const IntSize&);
> >     static BitmapInfo createBottomUp(const IntSize&);
> > };
> 
> That's a good idea.  Should this be in its own set of files, or is there
> someplace  else where this would make sense?

I think having its own files would be best.

> > > + void fillWithClearColor(HBITMAP);
> > 
> > I'm not sure what to do with this one.
> 
> The only thing that uses this is GraphicsContextWinXXXX, so I can just make it
> a method of the class and put it there.

Adding a new function to GraphicsContext.h seems a little ugly for this platform-specific function, especially since the function doesn't involve the GraphicsContext at all.

It looks like the only caller to fillWithClearColor is getWindowsContext. Can we do some refactoring to share that implementation, so that we don't need to find a way to share just this one function?
Comment 8 Brent Fulgham 2009-06-17 15:39:45 PDT
Created attachment 31453 [details]
Rev 3

Revised per Adam Roben's comments.
Comment 9 Adam Roben (:aroben) 2009-06-17 15:44:26 PDT
Comment on attachment 31453 [details]
Rev 3

This is looking great.

Since the 4 changes are each pretty self-contained, it would be much better to get them reviewed and landed as separate patches.

I also think the BitmapInfo functions should return a WebCore::BitmapInfo, not a BITMAPINFO.

r- so that these changes can be split up. Thanks for the great work!
Comment 10 Brent Fulgham 2009-06-17 16:04:46 PDT
Created attachment 31456 [details]
Part 1 (XFORM operator)

Add new XFORM operator to TransformationMatrix
Comment 11 Brent Fulgham 2009-06-17 16:14:14 PDT
Created attachment 31457 [details]
Part 2: (BitmapInfo structure)

This patch adds the BitmapInfo structure for later use in some refactoring.
Comment 12 Adam Roben (:aroben) 2009-06-17 16:17:37 PDT
Comment on attachment 31456 [details]
Part 1 (XFORM operator)

I don't think there's value in a patch that only adds the casting operator but doesn't use it. Can you put the code that uses it in this patch, too? Sorry for being unclear earlier.
Comment 13 Adam Roben (:aroben) 2009-06-17 16:18:00 PDT
Comment on attachment 31457 [details]
Part 2: (BitmapInfo structure)

Again, please put the code that uses the new functions in this patch. Sorry for being unclear.
Comment 14 Brent Fulgham 2009-06-17 16:35:17 PDT
Created attachment 31463 [details]
Part 3: (Use BitmapInfo Structure)

Depends on Patch #2.  Use BitmapInfo structure instead of manual structure assembly.
Comment 15 Brent Fulgham 2009-06-17 16:41:50 PDT
Created attachment 31465 [details]
Part 1: BitmapInfo Refactoring

Add a new BitmapInfo structure and use to refactor some duplicated code
Comment 16 Adam Roben (:aroben) 2009-06-17 16:45:30 PDT
Comment on attachment 31465 [details]
Part 1: BitmapInfo Refactoring

> +++ WebCore/ChangeLog	(working copy)
> @@ -1,3 +1,31 @@
> +2009-06-17  Brent Fulgham  <bfulgham@webkit.org>
> +
> +        Reviewed by NOBODY (OOPS!).
> +
> +        Refactor a few common routines in the various Windows ports
> +        and reduce some duplicated code.
> +
> +        Refactor use of BITMAPINFO for the new BitmapInfo structure.

You should mention the Bugzilla URL in your ChangeLog.

> +        BITMAPINFO bitmapInfo = BitmapInfo::create(dstRect.size());

Might as well use BitmapInfo here, too.

You could give BitmapInfo a constructor that initialized bmiHeader.biSize correctly and everything else to 0. That would follow the way ATL's C++ wrappers work. Or you could leave it like you have it now.

r=me
Comment 17 Brent Fulgham 2009-06-17 16:56:46 PDT
Created attachment 31467 [details]
Part 2: (Refactor XFORM)

Add new XFORM casting operator to TransformationMatrix, and use it to remove some duplicated code.

Push the concatCTM up from the CG- and Cairo-specific files into the generic GraphicsContextWin file.
Comment 18 Brent Fulgham 2009-06-17 17:34:01 PDT
Part 1 landed in https://trac.webkit.org/changeset/44789.
Comment 19 Adam Roben (:aroben) 2009-06-17 17:35:28 PDT
Comment on attachment 31467 [details]
Part 2: (Refactor XFORM)

>          // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
> -        XFORM xform;
> -        xform.eM11 = 1.0f;
> -        xform.eM12 = 0.0f;
> -        xform.eM21 = 0.0f;
> -        xform.eM22 = 1.0f;
> -        xform.eDx = -dstRect.x();
> -        xform.eDy = -dstRect.y();
> +        TransformationMatrix translate(1.0f, 0.0f, 0.0f, 1.0f, -dstRect.x(), -dstRect.y());
> +        XFORM xform = translate;

Maybe this would be better as:

XFORM xform = TransformationMatrix().translate(-dstRect.x(), -dstRect.y());

> -    XFORM xform;
> -    xform.eM11 = size.width();
> -    xform.eM12 = 0.0f;
> -    xform.eM21 = 0.0f;
> -    xform.eM22 = size.height();
> -    xform.eDx = 0.0f;
> -    xform.eDy = 0.0f;
> +
> +    TransformationMatrix scale(size.width(), 0.0f, 0.0f, size.height(), 0.0f, 0.0f);
> +
> +    XFORM xform = scale;

Maybe this would be better as:

XFORM xform = TransformationMatrix().scale(size.width(), size.height());

> -    XFORM xform;
> -    xform.eM11 = cosAngle;
> -    xform.eM12 = -sinAngle;
> -    xform.eM21 = sinAngle;
> -    xform.eM22 = cosAngle;
> -    xform.eDx = 0.0f;
> -    xform.eDy = 0.0f;
> +
> +    TransformationMatrix rotate(cosAngle, -sinAngle, sinAngle, cosAngle, 0.0f, 0.0f);
> +
> +    XFORM xform = rotate;

You could probably use TransformationMatrix::rotate() here, but I don't know the exactly incantation (probably just TransformationMatrix().rotate(degreesAngle)).

...and so on for the other cases.

r=me
Comment 20 Brent Fulgham 2009-06-17 21:19:21 PDT
Created attachment 31486 [details]
Part 3: (Move common logic to parent)

Add new 'flush' method to allow more common logic to be pushed to the parent file.
Comment 21 Eric Seidel (no email) 2009-06-18 13:42:45 PDT
Comment on attachment 31486 [details]
Part 3: (Move common logic to parent)

Assuming you're sure that the two getWindowsContext implementations are identical, than  this looks great!  r=me
Comment 22 Brent Fulgham 2009-06-18 13:49:43 PDT
Part 2 landed in http://trac.webkit.org/changeset/44793.
Comment 23 Brent Fulgham 2009-06-18 13:51:10 PDT
Part 3 landed in http://trac.webkit.org/changeset/44821.
Comment 24 Brent Fulgham 2009-06-18 14:07:28 PDT
Created attachment 31507 [details]
Part 4: (Final cleanups)

1. Move WinBitmap up so both ports can use it.
2. Use more concise TransformationMatrix syntax as suggested by Adam Roben in his earlier review.
Comment 25 Eric Seidel (no email) 2009-06-18 14:09:49 PDT
Comment on attachment 31507 [details]
Part 4: (Final cleanups)

LGTM.
Comment 26 Brent Fulgham 2009-06-18 17:31:28 PDT
Created attachment 31522 [details]
Part 5: (Some missed cleanups)

A handful of changes where the BitmapInfo struct can remove duplicated code.
Comment 27 David Levin 2009-06-18 18:12:47 PDT
Assigned to bfulgham to make it clear who is landing it.
Comment 28 Brent Fulgham 2009-06-18 20:49:19 PDT
Landed in http://trac.webkit.org/changeset/44836.