Bug 37440

Summary: [WINCE] Port tiled backing store
Product: WebKit Reporter: Kwang Yul Seo <skyul>
Component: PlatformAssignee: Nobody <webkit-unassigned>
Status: RESOLVED INVALID    
Severity: Normal CC: ahmad.saleem792, ap, bunhere, eric, hausmann, joybro201, kenneth, koivisto, zherczeg
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Other   
OS: Other   
Bug Depends on: 28272    
Bug Blocks:    
Attachments:
Description Flags
Patch
aroben: review-
patch
none
new patch kenneth: review-

Kwang Yul Seo
Reported 2010-04-12 00:29:12 PDT
Port tiled backing store to WinCE with SharedBitmap.
Attachments
Patch (9.47 KB, patch)
2010-04-12 00:32 PDT, Kwang Yul Seo
aroben: review-
patch (9.43 KB, patch)
2010-05-20 01:28 PDT, Young Han Lee
no flags
new patch (9.50 KB, patch)
2010-05-21 02:20 PDT, Young Han Lee
kenneth: review-
Kwang Yul Seo
Comment 1 2010-04-12 00:32:41 PDT
Created attachment 53156 [details] Patch This patch depends on SharedBitmap which is not yet upstreamed. I will submit a patch for SharedBitmap soon.
Zoltan Herczeg
Comment 2 2010-04-12 23:34:08 PDT
(In reply to comment #1) > Created an attachment (id=53156) [details] > Patch > > This patch depends on SharedBitmap which is not yet upstreamed. I will submit a > patch for SharedBitmap soon. Hm, looking at the Qt implementation, the target of paintCheckerPattern is not necessary checkerSize aligned, and might be scaled as well. Otherwise this patch seems ok.
Kwang Yul Seo
Comment 3 2010-04-13 21:34:29 PDT
I updated the SharedBitmap patch in bug 28272 as this patch depends on SharedBitmap.
Kwang Yul Seo
Comment 4 2010-04-14 21:01:34 PDT
(In reply to comment #2) > Hm, looking at the Qt implementation, the target of paintCheckerPattern is not > necessary checkerSize aligned, and might be scaled as well. Otherwise this > patch seems ok. You are right. I will fix it.
Eric Seidel (no email)
Comment 5 2010-05-09 14:23:35 PDT
What does Tile do? What ports use it? I'm still not sure why recent ports have had to add so many image-related classes.
Kenneth Rohde Christiansen
Comment 6 2010-05-09 16:29:23 PDT
(In reply to comment #5) > What does Tile do? What ports use it? I'm still not sure why recent ports have had to add so many image-related classes. Qt uses it, it is a tiled backing store that we are painting to, similar to what coregraphics does for the iphone port. So in that way it is not really related to images, but to painting.
Adam Roben (:aroben)
Comment 7 2010-05-13 10:46:18 PDT
Comment on attachment 53156 [details] Patch > + * platform/graphics/wince/TileWince.cpp: Added. This file should be named TileWinCE.cpp (see bug 37287). > + (WebCore::checkeredBitmap): > + (WebCore::Tile::Tile): > + (WebCore::Tile::~Tile): > + (WebCore::Tile::isDirty): > + (WebCore::Tile::isReadyToPaint): > + (WebCore::Tile::invalidate): > + (WebCore::enclosingRect): > + (WebCore::getUpdateRects): > + (WebCore::Tile::updateBackBuffer): > + (WebCore::Tile::swapBackBufferToFront): > + (WebCore::Tile::paint): > + (WebCore::Tile::paintCheckerPattern): Function-level comments are helpful to anyone trying to understand the patch. That includes reviewers and people in the future who are trying to figure out what the point of this patch was (if, e.g., it caused a regression or contained a bug). It's especially good if the comments explain the "why" of the patch, not just the "how". > +static PassRefPtr<SharedBitmap> checkeredBitmap() > +{ > + static RefPtr<SharedBitmap> bitmap; > + if (!bitmap) { > + bitmap = SharedBitmap::createInstance(true, checkerSize, checkerSize, false); > + unsigned key1, key2; > + HDC dc = bitmap->getDC(&key1, &key2); > + GraphicsContext context(dc); > + > + Color color1(checkerColor1); > + Color color2(checkerColor2); > + for (unsigned y = 0; y < checkerSize; y += checkerSize / 2) { > + bool alternate = y % checkerSize; > + for (unsigned x = 0; x < checkerSize; x += checkerSize / 2) { > + context.fillRect(FloatRect(x, y, checkerSize / 2, checkerSize / 2), > + alternate ? color1 : color2, DeviceColorSpace); > + alternate = !alternate; > + } > + } > + > + bitmap->releaseDC(dc, key1, key2); > + } > + return bitmap.release(); > +} It looks like this function is trying to create the bitmap just once and then return that single cached instance. But that's not the behavior it will have. RefPtr::release nulls out the RefPtr, so if (!bitmap) will always be true. I think instead you should change this function to return a bare pointer. It's a also slightly nicer style to have two separate functions: a "create" function that always allocates a new bitmap, and a getter that returns a single cached instance. Like this: static PassRefPtr<SharedBitmap> createCheckeredBitmap() { RefPtr<SharedBitmap> bitmap = SharedBitmap::createInstance(...); // Draw the checker pattern return bitmap.release(); } static SharedBitmap* checkeredBitmap() { static SharedBitmap* bitmap = createCheckeredBitmap().releaseRef(); return bitmap; } > +Tile::Tile(TiledBackingStore* backingStore, const Coordinate& tileCoordinate) > + : m_backingStore(backingStore) > + , m_coordinate(tileCoordinate) > + , m_rect(m_backingStore->tileRectForCoordinate(tileCoordinate)) > + , m_buffer(0) > + , m_backBuffer(0) No need to initialize m_buffer or m_backBuffer here. RefPtr does this for you automatically. > +static IntRect enclosingRect(HRGN hrgn) > +{ > + RECT r; > + GetRgnBox(hrgn, &r); > + return r; > +} > + This function is only called once. I'm not sure it's worth having a separate function for this. > +static void getUpdateRects(HRGN region, Vector<IntRect>& rects) > +{ > + const int rectThreshold = 10; > + const float wastedSpaceThreshold = 0.75f; > + > + IntRect dirtyRect(enclosingRect(region)); > + > + DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), 0); > + if (!regionDataSize) { > + rects.append(dirtyRect); > + return; > + } > + > + Vector<unsigned char> buffer(regionDataSize); > + RGNDATA* regionData = reinterpret_cast<RGNDATA*>(buffer.data()); > + GetRegionData(region, regionDataSize, regionData); > + if (regionData->rdh.nCount > rectThreshold) { > + rects.append(dirtyRect); > + return; > + } > + > + double singlePixels = 0.0; > + unsigned i; > + RECT* rect; > + for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++) > + singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top); > + > + double unionPixels = dirtyRect.width() * dirtyRect.height(); > + double wastedSpace = 1.0 - (singlePixels / unionPixels); > + if (wastedSpace <= wastedSpaceThreshold) { > + rects.append(dirtyRect); > + return; > + } > + > + for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++) > + rects.append(*rect); > +} This looks to be a copy of the function of the same name in WebKit/win/WebView.cpp. Can we share the code instead of duplicating it? > +void Tile::updateBackBuffer() > +{ > + if (m_buffer && !isDirty()) > + return; > + > + if (!m_backBuffer) { > + if (!m_buffer) > + m_backBuffer = SharedBitmap::createInstance( > + true, m_backingStore->m_tileSize.width(), m_backingStore->m_tileSize.height(), false); We normally would just put this all on one line. I think you should do that here. It would be nice if there were an overload of SharedBitmap::createInstance that took a const IntSize&. It would also be nice if it used enums instead of booleans, as I have no idea what "true" and "false" mean here. > + else { > + // Currently all buffers are updated synchronously at the same time so there is no real need > + // to have separate back and front buffers. Just use the existing buffer. If there's no need for two buffers, why do we have them? > + m_backBuffer = m_buffer; > + m_buffer = 0; You can do this more efficiently like this: m_backBuffer = m_buffer.release(); > + HRGN nullRegion = CreateRectRgn(0, 0, 0, 0); > + m_dirtyRegion.set(nullRegion); No need for the local nullRegion variable. > + int size = dirtyRects.size(); > + for (int n = 0; n < size; ++n) { It's a little better to use size_t instead of int when iterating over a Vector. > +void Tile::swapBackBufferToFront() > +{ > + if (!m_backBuffer) > + return; > + m_buffer = m_backBuffer; > + m_backBuffer = 0; > +} You can do this more efficiently like this: m_buffer = m_backBuffer.release(); > +void Tile::paint(GraphicsContext* context, const IntRect& rect) > +{ > + if (!m_buffer) > + return; > + > + IntRect target = intersection(rect, m_rect); > + IntRect source((target.x() - m_rect.x()), > + (target.y() - m_rect.y()), No need for the parentheses around these expressions. I'm also not sure all the newlines are making this more readable. > +void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target) > +{ > + FloatRect tileRectIn(0, 0, checkerSize, checkerSize); > + context->drawBitmapPattern(checkeredBitmap().get(), > + tileRectIn, > + AffineTransform(), > + FloatPoint(0, 0), You can just say FloatPoint() > + CompositeCopy, > + target, > + IntSize(checkerSize, checkerSize)); Is there no way to get the size from checkeredBitmap? It seems unfortunate to have to use the constants again here. Again, I don't think all the newlines are helping here.
Young Han Lee
Comment 8 2010-05-20 01:21:07 PDT
(In reply to comment #2) > (In reply to comment #1) > > Created an attachment (id=53156) [details] [details] > > Patch > > > > This patch depends on SharedBitmap which is not yet upstreamed. I will submit a > > patch for SharedBitmap soon. > > Hm, looking at the Qt implementation, the target of paintCheckerPattern is not necessary checkerSize aligned, and might be scaled as well. Otherwise this patch seems ok. The target doesn't be scaled and the checker is always displayed in same size.
Young Han Lee
Comment 9 2010-05-20 01:27:12 PDT
(In reply to comment #7) > (From update of attachment 53156 [details]) > > + * platform/graphics/wince/TileWince.cpp: Added. > > This file should be named TileWinCE.cpp (see bug 37287). > > > + (WebCore::checkeredBitmap): > > + (WebCore::Tile::Tile): > > + (WebCore::Tile::~Tile): > > + (WebCore::Tile::isDirty): > > + (WebCore::Tile::isReadyToPaint): > > + (WebCore::Tile::invalidate): > > + (WebCore::enclosingRect): > > + (WebCore::getUpdateRects): > > + (WebCore::Tile::updateBackBuffer): > > + (WebCore::Tile::swapBackBufferToFront): > > + (WebCore::Tile::paint): > > + (WebCore::Tile::paintCheckerPattern): > > Function-level comments are helpful to anyone trying to understand the patch. That includes reviewers and people in the future who are trying to figure out what the point of this patch was (if, e.g., it caused a regression or contained a bug). It's especially good if the comments explain the "why" of the patch, not just the "how". > > > +static PassRefPtr<SharedBitmap> checkeredBitmap() > > +{ > > + static RefPtr<SharedBitmap> bitmap; > > + if (!bitmap) { > > + bitmap = SharedBitmap::createInstance(true, checkerSize, checkerSize, false); > > + unsigned key1, key2; > > + HDC dc = bitmap->getDC(&key1, &key2); > > + GraphicsContext context(dc); > > + > > + Color color1(checkerColor1); > > + Color color2(checkerColor2); > > + for (unsigned y = 0; y < checkerSize; y += checkerSize / 2) { > > + bool alternate = y % checkerSize; > > + for (unsigned x = 0; x < checkerSize; x += checkerSize / 2) { > > + context.fillRect(FloatRect(x, y, checkerSize / 2, checkerSize / 2), > > + alternate ? color1 : color2, DeviceColorSpace); > > + alternate = !alternate; > > + } > > + } > > + > > + bitmap->releaseDC(dc, key1, key2); > > + } > > + return bitmap.release(); > > +} > > It looks like this function is trying to create the bitmap just once and then return that single cached instance. But that's not the behavior it will have. RefPtr::release nulls out the RefPtr, so if (!bitmap) will always be true. > > I think instead you should change this function to return a bare pointer. It's a also slightly nicer style to have two separate functions: a "create" function that always allocates a new bitmap, and a getter that returns a single cached instance. Like this: > > static PassRefPtr<SharedBitmap> createCheckeredBitmap() > { > RefPtr<SharedBitmap> bitmap = SharedBitmap::createInstance(...); > // Draw the checker pattern > return bitmap.release(); > } > > static SharedBitmap* checkeredBitmap() > { > static SharedBitmap* bitmap = createCheckeredBitmap().releaseRef(); > return bitmap; > } > > > +Tile::Tile(TiledBackingStore* backingStore, const Coordinate& tileCoordinate) > > + : m_backingStore(backingStore) > > + , m_coordinate(tileCoordinate) > > + , m_rect(m_backingStore->tileRectForCoordinate(tileCoordinate)) > > + , m_buffer(0) > > + , m_backBuffer(0) > > No need to initialize m_buffer or m_backBuffer here. RefPtr does this for you automatically. > > > +static IntRect enclosingRect(HRGN hrgn) > > +{ > > + RECT r; > > + GetRgnBox(hrgn, &r); > > + return r; > > +} > > + > > This function is only called once. I'm not sure it's worth having a separate function for this. > > > +static void getUpdateRects(HRGN region, Vector<IntRect>& rects) > > +{ > > + const int rectThreshold = 10; > > + const float wastedSpaceThreshold = 0.75f; > > + > > + IntRect dirtyRect(enclosingRect(region)); > > + > > + DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), 0); > > + if (!regionDataSize) { > > + rects.append(dirtyRect); > > + return; > > + } > > + > > + Vector<unsigned char> buffer(regionDataSize); > > + RGNDATA* regionData = reinterpret_cast<RGNDATA*>(buffer.data()); > > + GetRegionData(region, regionDataSize, regionData); > > + if (regionData->rdh.nCount > rectThreshold) { > > + rects.append(dirtyRect); > > + return; > > + } > > + > > + double singlePixels = 0.0; > > + unsigned i; > > + RECT* rect; > > + for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++) > > + singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top); > > + > > + double unionPixels = dirtyRect.width() * dirtyRect.height(); > > + double wastedSpace = 1.0 - (singlePixels / unionPixels); > > + if (wastedSpace <= wastedSpaceThreshold) { > > + rects.append(dirtyRect); > > + return; > > + } > > + > > + for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++) > > + rects.append(*rect); > > +} > > This looks to be a copy of the function of the same name in WebKit/win/WebView.cpp. Can we share the code instead of duplicating it? > > > +void Tile::updateBackBuffer() > > +{ > > + if (m_buffer && !isDirty()) > > + return; > > + > > + if (!m_backBuffer) { > > + if (!m_buffer) > > + m_backBuffer = SharedBitmap::createInstance( > > + true, m_backingStore->m_tileSize.width(), m_backingStore->m_tileSize.height(), false); > > We normally would just put this all on one line. I think you should do that here. > > It would be nice if there were an overload of SharedBitmap::createInstance that took a const IntSize&. It would also be nice if it used enums instead of booleans, as I have no idea what "true" and "false" mean here. > > > + else { > > + // Currently all buffers are updated synchronously at the same time so there is no real need > > + // to have separate back and front buffers. Just use the existing buffer. > > If there's no need for two buffers, why do we have them? > > > + m_backBuffer = m_buffer; > > + m_buffer = 0; > > You can do this more efficiently like this: > > m_backBuffer = m_buffer.release(); > > > + HRGN nullRegion = CreateRectRgn(0, 0, 0, 0); > > + m_dirtyRegion.set(nullRegion); > > No need for the local nullRegion variable. > > > + int size = dirtyRects.size(); > > + for (int n = 0; n < size; ++n) { > > It's a little better to use size_t instead of int when iterating over a Vector. > > > +void Tile::swapBackBufferToFront() > > +{ > > + if (!m_backBuffer) > > + return; > > + m_buffer = m_backBuffer; > > + m_backBuffer = 0; > > +} > > You can do this more efficiently like this: > > m_buffer = m_backBuffer.release(); > > > +void Tile::paint(GraphicsContext* context, const IntRect& rect) > > +{ > > + if (!m_buffer) > > + return; > > + > > + IntRect target = intersection(rect, m_rect); > > + IntRect source((target.x() - m_rect.x()), > > + (target.y() - m_rect.y()), > > No need for the parentheses around these expressions. I'm also not sure all the newlines are making this more readable. > > > +void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target) > > +{ > > + FloatRect tileRectIn(0, 0, checkerSize, checkerSize); > > + context->drawBitmapPattern(checkeredBitmap().get(), > > + tileRectIn, > > + AffineTransform(), > > + FloatPoint(0, 0), > > You can just say FloatPoint() > > > + CompositeCopy, > > + target, > > + IntSize(checkerSize, checkerSize)); > > Is there no way to get the size from checkeredBitmap? It seems unfortunate to have to use the constants again here. > > Again, I don't think all the newlines are helping here. I accepted all your points except a few works seems like overwork. We could consider it later.
Young Han Lee
Comment 10 2010-05-20 01:28:38 PDT
Young Han Lee
Comment 11 2010-05-20 01:48:12 PDT
Comment on attachment 56574 [details] patch There were some mistakes. sorry.
Young Han Lee
Comment 12 2010-05-21 02:20:28 PDT
Created attachment 56686 [details] new patch Here is the patch I intended to attach, sorry for the confusion.
Simon Hausmann
Comment 13 2010-08-04 13:10:52 PDT
Comment on attachment 56686 [details] new patch WebCore/platform/graphics/wince/TileWinCE.cpp:117 + static void getUpdateRects(HRGN region, Vector<IntRect>& rects) Before this function you define the convenient enclosingRect() helper function, and a few lines into this function you call GetRgnBox instead of the newly defined helper functions. I suggest to make use of it :) The rest of the patch looks okay to me, although I pity you guys for having to use HRGN :)
Kenneth Rohde Christiansen
Comment 14 2010-08-14 08:19:43 PDT
Comment on attachment 56686 [details] new patch r- due to Simon Hausmann's comment.
Ahmad Saleem
Comment 15 2023-01-22 14:16:56 PST
@ap - WINCE port exist? I don't think so.. Can we close this?
Note You need to log in before you can comment on or make changes to this bug.