|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "mozilla/layers/ContentHost.h" |
|
7 #include "LayersLogging.h" // for AppendToString |
|
8 #include "gfx2DGlue.h" // for ContentForFormat |
|
9 #include "mozilla/gfx/Point.h" // for IntSize |
|
10 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
|
11 #include "mozilla/gfx/BaseRect.h" // for BaseRect |
|
12 #include "mozilla/layers/Compositor.h" // for Compositor |
|
13 #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc |
|
14 #include "mozilla/layers/LayersMessages.h" // for ThebesBufferData |
|
15 #include "nsAString.h" |
|
16 #include "nsPrintfCString.h" // for nsPrintfCString |
|
17 #include "nsString.h" // for nsAutoCString |
|
18 #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL |
|
19 |
|
20 namespace mozilla { |
|
21 namespace gfx { |
|
22 class Matrix4x4; |
|
23 } |
|
24 using namespace gfx; |
|
25 |
|
26 namespace layers { |
|
27 |
|
28 ContentHostBase::ContentHostBase(const TextureInfo& aTextureInfo) |
|
29 : ContentHost(aTextureInfo) |
|
30 , mPaintWillResample(false) |
|
31 , mInitialised(false) |
|
32 {} |
|
33 |
|
34 ContentHostBase::~ContentHostBase() |
|
35 { |
|
36 } |
|
37 |
|
38 struct AutoLockContentHost |
|
39 { |
|
40 AutoLockContentHost(ContentHostBase* aHost) |
|
41 : mHost(aHost) |
|
42 { |
|
43 mSucceeded = mHost->Lock(); |
|
44 } |
|
45 |
|
46 ~AutoLockContentHost() |
|
47 { |
|
48 if (mSucceeded) { |
|
49 mHost->Unlock(); |
|
50 } |
|
51 } |
|
52 |
|
53 bool Failed() { return !mSucceeded; } |
|
54 |
|
55 ContentHostBase* mHost; |
|
56 bool mSucceeded; |
|
57 }; |
|
58 |
|
59 void |
|
60 ContentHostBase::Composite(EffectChain& aEffectChain, |
|
61 float aOpacity, |
|
62 const gfx::Matrix4x4& aTransform, |
|
63 const Filter& aFilter, |
|
64 const Rect& aClipRect, |
|
65 const nsIntRegion* aVisibleRegion, |
|
66 TiledLayerProperties* aLayerProperties) |
|
67 { |
|
68 NS_ASSERTION(aVisibleRegion, "Requires a visible region"); |
|
69 |
|
70 AutoLockContentHost lock(this); |
|
71 if (lock.Failed()) { |
|
72 return; |
|
73 } |
|
74 |
|
75 RefPtr<NewTextureSource> source = GetTextureSource(); |
|
76 RefPtr<NewTextureSource> sourceOnWhite = GetTextureSourceOnWhite(); |
|
77 |
|
78 if (!source) { |
|
79 return; |
|
80 } |
|
81 RefPtr<TexturedEffect> effect = |
|
82 CreateTexturedEffect(source, sourceOnWhite, aFilter); |
|
83 |
|
84 if (!effect) { |
|
85 return; |
|
86 } |
|
87 |
|
88 aEffectChain.mPrimaryEffect = effect; |
|
89 |
|
90 nsIntRegion tmpRegion; |
|
91 const nsIntRegion* renderRegion; |
|
92 if (PaintWillResample()) { |
|
93 // If we're resampling, then the texture image will contain exactly the |
|
94 // entire visible region's bounds, and we should draw it all in one quad |
|
95 // to avoid unexpected aliasing. |
|
96 tmpRegion = aVisibleRegion->GetBounds(); |
|
97 renderRegion = &tmpRegion; |
|
98 } else { |
|
99 renderRegion = aVisibleRegion; |
|
100 } |
|
101 |
|
102 nsIntRegion region(*renderRegion); |
|
103 nsIntPoint origin = GetOriginOffset(); |
|
104 // translate into TexImage space, buffer origin might not be at texture (0,0) |
|
105 region.MoveBy(-origin); |
|
106 |
|
107 // Figure out the intersecting draw region |
|
108 gfx::IntSize texSize = source->GetSize(); |
|
109 nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height); |
|
110 textureRect.MoveBy(region.GetBounds().TopLeft()); |
|
111 nsIntRegion subregion; |
|
112 subregion.And(region, textureRect); |
|
113 if (subregion.IsEmpty()) { |
|
114 // Region is empty, nothing to draw |
|
115 return; |
|
116 } |
|
117 |
|
118 nsIntRegion screenRects; |
|
119 nsIntRegion regionRects; |
|
120 |
|
121 // Collect texture/screen coordinates for drawing |
|
122 nsIntRegionRectIterator iter(subregion); |
|
123 while (const nsIntRect* iterRect = iter.Next()) { |
|
124 nsIntRect regionRect = *iterRect; |
|
125 nsIntRect screenRect = regionRect; |
|
126 screenRect.MoveBy(origin); |
|
127 |
|
128 screenRects.Or(screenRects, screenRect); |
|
129 regionRects.Or(regionRects, regionRect); |
|
130 } |
|
131 |
|
132 TileIterator* tileIter = source->AsTileIterator(); |
|
133 TileIterator* iterOnWhite = nullptr; |
|
134 if (tileIter) { |
|
135 tileIter->BeginTileIteration(); |
|
136 } |
|
137 |
|
138 if (sourceOnWhite) { |
|
139 iterOnWhite = sourceOnWhite->AsTileIterator(); |
|
140 MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(), |
|
141 "Tile count mismatch on component alpha texture"); |
|
142 if (iterOnWhite) { |
|
143 iterOnWhite->BeginTileIteration(); |
|
144 } |
|
145 } |
|
146 |
|
147 bool usingTiles = (tileIter && tileIter->GetTileCount() > 1); |
|
148 do { |
|
149 if (iterOnWhite) { |
|
150 MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(), |
|
151 "component alpha textures should be the same size."); |
|
152 } |
|
153 |
|
154 nsIntRect texRect = tileIter ? tileIter->GetTileRect() |
|
155 : nsIntRect(0, 0, |
|
156 texSize.width, |
|
157 texSize.height); |
|
158 |
|
159 // Draw texture. If we're using tiles, we do repeating manually, as texture |
|
160 // repeat would cause each individual tile to repeat instead of the |
|
161 // compound texture as a whole. This involves drawing at most 4 sections, |
|
162 // 2 for each axis that has texture repeat. |
|
163 for (int y = 0; y < (usingTiles ? 2 : 1); y++) { |
|
164 for (int x = 0; x < (usingTiles ? 2 : 1); x++) { |
|
165 nsIntRect currentTileRect(texRect); |
|
166 currentTileRect.MoveBy(x * texSize.width, y * texSize.height); |
|
167 |
|
168 nsIntRegionRectIterator screenIter(screenRects); |
|
169 nsIntRegionRectIterator regionIter(regionRects); |
|
170 |
|
171 const nsIntRect* screenRect; |
|
172 const nsIntRect* regionRect; |
|
173 while ((screenRect = screenIter.Next()) && |
|
174 (regionRect = regionIter.Next())) { |
|
175 nsIntRect tileScreenRect(*screenRect); |
|
176 nsIntRect tileRegionRect(*regionRect); |
|
177 |
|
178 // When we're using tiles, find the intersection between the tile |
|
179 // rect and this region rect. Tiling is then handled by the |
|
180 // outer for-loops and modifying the tile rect. |
|
181 if (usingTiles) { |
|
182 tileScreenRect.MoveBy(-origin); |
|
183 tileScreenRect = tileScreenRect.Intersect(currentTileRect); |
|
184 tileScreenRect.MoveBy(origin); |
|
185 |
|
186 if (tileScreenRect.IsEmpty()) |
|
187 continue; |
|
188 |
|
189 tileRegionRect = regionRect->Intersect(currentTileRect); |
|
190 tileRegionRect.MoveBy(-currentTileRect.TopLeft()); |
|
191 } |
|
192 gfx::Rect rect(tileScreenRect.x, tileScreenRect.y, |
|
193 tileScreenRect.width, tileScreenRect.height); |
|
194 |
|
195 effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width, |
|
196 Float(tileRegionRect.y) / texRect.height, |
|
197 Float(tileRegionRect.width) / texRect.width, |
|
198 Float(tileRegionRect.height) / texRect.height); |
|
199 GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform); |
|
200 if (usingTiles) { |
|
201 DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE; |
|
202 diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; |
|
203 GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect, |
|
204 aTransform, mFlashCounter); |
|
205 } |
|
206 } |
|
207 } |
|
208 } |
|
209 |
|
210 if (iterOnWhite) { |
|
211 iterOnWhite->NextTile(); |
|
212 } |
|
213 } while (usingTiles && tileIter->NextTile()); |
|
214 |
|
215 if (tileIter) { |
|
216 tileIter->EndTileIteration(); |
|
217 } |
|
218 if (iterOnWhite) { |
|
219 iterOnWhite->EndTileIteration(); |
|
220 } |
|
221 |
|
222 DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT; |
|
223 diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; |
|
224 GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect, |
|
225 aTransform, mFlashCounter); |
|
226 } |
|
227 |
|
228 |
|
229 void |
|
230 ContentHostTexture::UseTextureHost(TextureHost* aTexture) |
|
231 { |
|
232 ContentHostBase::UseTextureHost(aTexture); |
|
233 mTextureHost = aTexture; |
|
234 mTextureHostOnWhite = nullptr; |
|
235 } |
|
236 |
|
237 void |
|
238 ContentHostTexture::UseComponentAlphaTextures(TextureHost* aTextureOnBlack, |
|
239 TextureHost* aTextureOnWhite) |
|
240 { |
|
241 ContentHostBase::UseComponentAlphaTextures(aTextureOnBlack, aTextureOnWhite); |
|
242 mTextureHost = aTextureOnBlack; |
|
243 mTextureHostOnWhite = aTextureOnWhite; |
|
244 } |
|
245 |
|
246 void |
|
247 ContentHostTexture::SetCompositor(Compositor* aCompositor) |
|
248 { |
|
249 ContentHostBase::SetCompositor(aCompositor); |
|
250 if (mTextureHost) { |
|
251 mTextureHost->SetCompositor(aCompositor); |
|
252 } |
|
253 if (mTextureHostOnWhite) { |
|
254 mTextureHostOnWhite->SetCompositor(aCompositor); |
|
255 } |
|
256 } |
|
257 |
|
258 #ifdef MOZ_DUMP_PAINTING |
|
259 void |
|
260 ContentHostTexture::Dump(FILE* aFile, |
|
261 const char* aPrefix, |
|
262 bool aDumpHtml) |
|
263 { |
|
264 if (!aDumpHtml) { |
|
265 return; |
|
266 } |
|
267 if (!aFile) { |
|
268 aFile = stderr; |
|
269 } |
|
270 fprintf(aFile, "<ul>"); |
|
271 if (mTextureHost) { |
|
272 fprintf(aFile, "%s", aPrefix); |
|
273 fprintf(aFile, "<li> <a href="); |
|
274 DumpTextureHost(aFile, mTextureHost); |
|
275 fprintf(aFile, "> Front buffer </a></li> "); |
|
276 } |
|
277 if (mTextureHostOnWhite) { |
|
278 fprintf(aFile, "%s", aPrefix); |
|
279 fprintf(aFile, "<li> <a href="); |
|
280 DumpTextureHost(aFile, mTextureHostOnWhite); |
|
281 fprintf(aFile, "> Front buffer on white </a> </li> "); |
|
282 } |
|
283 fprintf(aFile, "</ul>"); |
|
284 } |
|
285 #endif |
|
286 |
|
287 static inline void |
|
288 AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput, |
|
289 const nsIntSize& aSize, const nsIntPoint& aShift) |
|
290 { |
|
291 nsIntRegion tempRegion; |
|
292 tempRegion.And(nsIntRect(aShift, aSize), aInput); |
|
293 tempRegion.MoveBy(-aShift); |
|
294 aOutput.Or(aOutput, tempRegion); |
|
295 } |
|
296 |
|
297 bool |
|
298 ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData, |
|
299 const nsIntRegion& aUpdated, |
|
300 const nsIntRegion& aOldValidRegionBack, |
|
301 nsIntRegion* aUpdatedRegionBack) |
|
302 { |
|
303 aUpdatedRegionBack->SetEmpty(); |
|
304 |
|
305 if (!mTextureHost) { |
|
306 mInitialised = false; |
|
307 return true; // FIXME should we return false? Returning true for now |
|
308 } // to preserve existing behavior of NOT causing IPC errors. |
|
309 |
|
310 // updated is in screen coordinates. Convert it to buffer coordinates. |
|
311 nsIntRegion destRegion(aUpdated); |
|
312 destRegion.MoveBy(-aData.rect().TopLeft()); |
|
313 |
|
314 if (!aData.rect().Contains(aUpdated.GetBounds()) || |
|
315 aData.rotation().x > aData.rect().width || |
|
316 aData.rotation().y > aData.rect().height) { |
|
317 NS_ERROR("Invalid update data"); |
|
318 return false; |
|
319 } |
|
320 |
|
321 // destRegion is now in logical coordinates relative to the buffer, but we |
|
322 // need to account for rotation. We do that by moving the region to the |
|
323 // rotation offset and then wrapping any pixels that extend off the |
|
324 // bottom/right edges. |
|
325 |
|
326 // Shift to the rotation point |
|
327 destRegion.MoveBy(aData.rotation()); |
|
328 |
|
329 nsIntSize bufferSize = aData.rect().Size(); |
|
330 |
|
331 // Select only the pixels that are still within the buffer. |
|
332 nsIntRegion finalRegion; |
|
333 finalRegion.And(nsIntRect(nsIntPoint(), bufferSize), destRegion); |
|
334 |
|
335 // For each of the overlap areas (right, bottom-right, bottom), select those |
|
336 // pixels and wrap them around to the opposite edge of the buffer rect. |
|
337 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, 0)); |
|
338 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, aData.rect().height)); |
|
339 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().height)); |
|
340 |
|
341 MOZ_ASSERT(nsIntRect(0, 0, aData.rect().width, aData.rect().height).Contains(finalRegion.GetBounds())); |
|
342 |
|
343 mTextureHost->Updated(&finalRegion); |
|
344 if (mTextureHostOnWhite) { |
|
345 mTextureHostOnWhite->Updated(&finalRegion); |
|
346 } |
|
347 mInitialised = true; |
|
348 |
|
349 mBufferRect = aData.rect(); |
|
350 mBufferRotation = aData.rotation(); |
|
351 |
|
352 return true; |
|
353 } |
|
354 |
|
355 bool |
|
356 ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData, |
|
357 const nsIntRegion& aUpdated, |
|
358 const nsIntRegion& aOldValidRegionBack, |
|
359 nsIntRegion* aUpdatedRegionBack) |
|
360 { |
|
361 if (!mTextureHost) { |
|
362 mInitialised = false; |
|
363 |
|
364 *aUpdatedRegionBack = aUpdated; |
|
365 return true; |
|
366 } |
|
367 |
|
368 // We don't need to calculate an update region because we assume that if we |
|
369 // are using double buffering then we have render-to-texture and thus no |
|
370 // upload to do. |
|
371 mTextureHost->Updated(); |
|
372 if (mTextureHostOnWhite) { |
|
373 mTextureHostOnWhite->Updated(); |
|
374 } |
|
375 mInitialised = true; |
|
376 |
|
377 mBufferRect = aData.rect(); |
|
378 mBufferRotation = aData.rotation(); |
|
379 |
|
380 *aUpdatedRegionBack = aUpdated; |
|
381 |
|
382 // Save the current valid region of our front buffer, because if |
|
383 // we're double buffering, it's going to be the valid region for the |
|
384 // next back buffer sent back to the renderer. |
|
385 // |
|
386 // NB: we rely here on the fact that mValidRegion is initialized to |
|
387 // empty, and that the first time Swap() is called we don't have a |
|
388 // valid front buffer that we're going to return to content. |
|
389 mValidRegionForNextBackBuffer = aOldValidRegionBack; |
|
390 |
|
391 return true; |
|
392 } |
|
393 |
|
394 ContentHostIncremental::ContentHostIncremental(const TextureInfo& aTextureInfo) |
|
395 : ContentHostBase(aTextureInfo) |
|
396 , mDeAllocator(nullptr) |
|
397 , mLocked(false) |
|
398 { |
|
399 } |
|
400 |
|
401 ContentHostIncremental::~ContentHostIncremental() |
|
402 { |
|
403 } |
|
404 |
|
405 bool |
|
406 ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator, |
|
407 const TextureInfo& aTextureInfo, |
|
408 const nsIntRect& aBufferRect) |
|
409 { |
|
410 mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo, |
|
411 aBufferRect)); |
|
412 mDeAllocator = aAllocator; |
|
413 FlushUpdateQueue(); |
|
414 return true; |
|
415 } |
|
416 |
|
417 void |
|
418 ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId, |
|
419 SurfaceDescriptor& aSurface, |
|
420 const nsIntRegion& aUpdated, |
|
421 const nsIntRect& aBufferRect, |
|
422 const nsIntPoint& aBufferRotation) |
|
423 { |
|
424 mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator, |
|
425 aTextureId, |
|
426 aSurface, |
|
427 aUpdated, |
|
428 aBufferRect, |
|
429 aBufferRotation)); |
|
430 FlushUpdateQueue(); |
|
431 } |
|
432 |
|
433 void |
|
434 ContentHostIncremental::FlushUpdateQueue() |
|
435 { |
|
436 // If we're not compositing for some reason (the window being minimized |
|
437 // is one example), then we never process these updates and it can consume |
|
438 // huge amounts of memory. Instead we forcibly process the updates (during the |
|
439 // transaction) if the list gets too long. |
|
440 static const uint32_t kMaxUpdateCount = 6; |
|
441 if (mUpdateList.Length() >= kMaxUpdateCount) { |
|
442 ProcessTextureUpdates(); |
|
443 } |
|
444 } |
|
445 |
|
446 void |
|
447 ContentHostIncremental::ProcessTextureUpdates() |
|
448 { |
|
449 for (uint32_t i = 0; i < mUpdateList.Length(); i++) { |
|
450 mUpdateList[i]->Execute(this); |
|
451 } |
|
452 mUpdateList.Clear(); |
|
453 } |
|
454 |
|
455 NewTextureSource* |
|
456 ContentHostIncremental::GetTextureSource() |
|
457 { |
|
458 MOZ_ASSERT(mLocked); |
|
459 return mSource; |
|
460 } |
|
461 |
|
462 NewTextureSource* |
|
463 ContentHostIncremental::GetTextureSourceOnWhite() |
|
464 { |
|
465 MOZ_ASSERT(mLocked); |
|
466 return mSourceOnWhite; |
|
467 } |
|
468 |
|
469 void |
|
470 ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost) |
|
471 { |
|
472 Compositor* compositor = aHost->GetCompositor(); |
|
473 MOZ_ASSERT(compositor); |
|
474 |
|
475 RefPtr<DataTextureSource> temp = |
|
476 compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags); |
|
477 MOZ_ASSERT(temp->AsSourceOGL() && |
|
478 temp->AsSourceOGL()->AsTextureImageTextureSource()); |
|
479 RefPtr<TextureImageTextureSourceOGL> newSource = |
|
480 temp->AsSourceOGL()->AsTextureImageTextureSource(); |
|
481 |
|
482 RefPtr<TextureImageTextureSourceOGL> newSourceOnWhite; |
|
483 if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) { |
|
484 temp = |
|
485 compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags); |
|
486 MOZ_ASSERT(temp->AsSourceOGL() && |
|
487 temp->AsSourceOGL()->AsTextureImageTextureSource()); |
|
488 newSourceOnWhite = temp->AsSourceOGL()->AsTextureImageTextureSource(); |
|
489 } |
|
490 |
|
491 if (mTextureInfo.mDeprecatedTextureHostFlags & TEXTURE_HOST_COPY_PREVIOUS) { |
|
492 MOZ_ASSERT(aHost->mSource); |
|
493 MOZ_ASSERT(aHost->mSource->IsValid()); |
|
494 nsIntRect bufferRect = aHost->mBufferRect; |
|
495 nsIntPoint bufferRotation = aHost->mBufferRotation; |
|
496 nsIntRect overlap; |
|
497 |
|
498 // The buffer looks like: |
|
499 // ______ |
|
500 // |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner. |
|
501 // |___|__| |
|
502 // |3 |4 | |
|
503 // |___|__| |
|
504 // |
|
505 // This is drawn to the screen as: |
|
506 // ______ |
|
507 // |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from |
|
508 // |___|__| from the top left corner - rotationPoint. |
|
509 // |2 |1 | |
|
510 // |___|__| |
|
511 // |
|
512 |
|
513 // The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles |
|
514 // in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified. |
|
515 |
|
516 nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y); |
|
517 nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y); |
|
518 nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y); |
|
519 nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y); |
|
520 |
|
521 overlap.IntersectRect(bufferRect, mBufferRect); |
|
522 |
|
523 nsIntRect srcRect(overlap), dstRect(overlap); |
|
524 srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation); |
|
525 |
|
526 nsIntRect srcRectDrawTopRight(srcRect); |
|
527 nsIntRect srcRectDrawTopLeft(srcRect); |
|
528 nsIntRect srcRectDrawBottomLeft(srcRect); |
|
529 // transform into the different quadrants |
|
530 srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height)); |
|
531 srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height)); |
|
532 srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0)); |
|
533 |
|
534 // Intersect with the quadrant |
|
535 srcRect = srcRect .Intersect(srcBufferSpaceBottomRight); |
|
536 srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight); |
|
537 srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft); |
|
538 srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft); |
|
539 |
|
540 dstRect = srcRect; |
|
541 nsIntRect dstRectDrawTopRight(srcRectDrawTopRight); |
|
542 nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft); |
|
543 nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft); |
|
544 |
|
545 // transform back to src buffer space |
|
546 dstRect .MoveBy(-bufferRotation); |
|
547 dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height)); |
|
548 dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height)); |
|
549 dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0)); |
|
550 |
|
551 // transform back to draw coordinates |
|
552 dstRect .MoveBy(bufferRect.TopLeft()); |
|
553 dstRectDrawTopRight .MoveBy(bufferRect.TopLeft()); |
|
554 dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft()); |
|
555 dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft()); |
|
556 |
|
557 // transform to destBuffer space |
|
558 dstRect .MoveBy(-mBufferRect.TopLeft()); |
|
559 dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft()); |
|
560 dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft()); |
|
561 dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft()); |
|
562 |
|
563 newSource->EnsureBuffer(mBufferRect.Size(), |
|
564 ContentForFormat(aHost->mSource->GetFormat())); |
|
565 |
|
566 aHost->mSource->CopyTo(srcRect, newSource, dstRect); |
|
567 if (bufferRotation != nsIntPoint(0, 0)) { |
|
568 // Draw the remaining quadrants. We call BlitTextureImage 3 extra |
|
569 // times instead of doing a single draw call because supporting that |
|
570 // with a tiled source is quite tricky. |
|
571 |
|
572 if (!srcRectDrawTopRight.IsEmpty()) |
|
573 aHost->mSource->CopyTo(srcRectDrawTopRight, |
|
574 newSource, dstRectDrawTopRight); |
|
575 if (!srcRectDrawTopLeft.IsEmpty()) |
|
576 aHost->mSource->CopyTo(srcRectDrawTopLeft, |
|
577 newSource, dstRectDrawTopLeft); |
|
578 if (!srcRectDrawBottomLeft.IsEmpty()) |
|
579 aHost->mSource->CopyTo(srcRectDrawBottomLeft, |
|
580 newSource, dstRectDrawBottomLeft); |
|
581 } |
|
582 |
|
583 if (newSourceOnWhite) { |
|
584 newSourceOnWhite->EnsureBuffer(mBufferRect.Size(), |
|
585 ContentForFormat(aHost->mSourceOnWhite->GetFormat())); |
|
586 aHost->mSourceOnWhite->CopyTo(srcRect, newSourceOnWhite, dstRect); |
|
587 if (bufferRotation != nsIntPoint(0, 0)) { |
|
588 // draw the remaining quadrants |
|
589 if (!srcRectDrawTopRight.IsEmpty()) |
|
590 aHost->mSourceOnWhite->CopyTo(srcRectDrawTopRight, |
|
591 newSourceOnWhite, dstRectDrawTopRight); |
|
592 if (!srcRectDrawTopLeft.IsEmpty()) |
|
593 aHost->mSourceOnWhite->CopyTo(srcRectDrawTopLeft, |
|
594 newSourceOnWhite, dstRectDrawTopLeft); |
|
595 if (!srcRectDrawBottomLeft.IsEmpty()) |
|
596 aHost->mSourceOnWhite->CopyTo(srcRectDrawBottomLeft, |
|
597 newSourceOnWhite, dstRectDrawBottomLeft); |
|
598 } |
|
599 } |
|
600 } |
|
601 |
|
602 aHost->mSource = newSource; |
|
603 aHost->mSourceOnWhite = newSourceOnWhite; |
|
604 |
|
605 aHost->mBufferRect = mBufferRect; |
|
606 aHost->mBufferRotation = nsIntPoint(); |
|
607 } |
|
608 |
|
609 nsIntRect |
|
610 ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide, |
|
611 YSide aYSide) const |
|
612 { |
|
613 // quadrantTranslation is the amount we translate the top-left |
|
614 // of the quadrant by to get coordinates relative to the layer |
|
615 nsIntPoint quadrantTranslation = -mBufferRotation; |
|
616 quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0; |
|
617 quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0; |
|
618 return mBufferRect + quadrantTranslation; |
|
619 } |
|
620 |
|
621 void |
|
622 ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost) |
|
623 { |
|
624 nsIntRect drawBounds = mUpdated.GetBounds(); |
|
625 |
|
626 aHost->mBufferRect = mBufferRect; |
|
627 aHost->mBufferRotation = mBufferRotation; |
|
628 |
|
629 // Figure out which quadrant to draw in |
|
630 int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x; |
|
631 int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y; |
|
632 XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT; |
|
633 YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP; |
|
634 nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY); |
|
635 NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants"); |
|
636 |
|
637 mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y)); |
|
638 |
|
639 IntPoint offset = ToIntPoint(-mUpdated.GetBounds().TopLeft()); |
|
640 |
|
641 RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(mDescriptor); |
|
642 |
|
643 if (mTextureId == TextureFront) { |
|
644 aHost->mSource->Update(surf, &mUpdated, &offset); |
|
645 } else { |
|
646 aHost->mSourceOnWhite->Update(surf, &mUpdated, &offset); |
|
647 } |
|
648 } |
|
649 |
|
650 void |
|
651 ContentHostTexture::PrintInfo(nsACString& aTo, const char* aPrefix) |
|
652 { |
|
653 aTo += aPrefix; |
|
654 aTo += nsPrintfCString("ContentHost (0x%p)", this); |
|
655 |
|
656 AppendToString(aTo, mBufferRect, " [buffer-rect=", "]"); |
|
657 AppendToString(aTo, mBufferRotation, " [buffer-rotation=", "]"); |
|
658 if (PaintWillResample()) { |
|
659 aTo += " [paint-will-resample]"; |
|
660 } |
|
661 |
|
662 nsAutoCString pfx(aPrefix); |
|
663 pfx += " "; |
|
664 |
|
665 if (mTextureHost) { |
|
666 aTo += "\n"; |
|
667 mTextureHost->PrintInfo(aTo, pfx.get()); |
|
668 } |
|
669 } |
|
670 |
|
671 |
|
672 LayerRenderState |
|
673 ContentHostTexture::GetRenderState() |
|
674 { |
|
675 if (!mTextureHost) { |
|
676 return LayerRenderState(); |
|
677 } |
|
678 |
|
679 LayerRenderState result = mTextureHost->GetRenderState(); |
|
680 |
|
681 if (mBufferRotation != nsIntPoint()) { |
|
682 result.mFlags |= LAYER_RENDER_STATE_BUFFER_ROTATION; |
|
683 } |
|
684 result.SetOffset(GetOriginOffset()); |
|
685 return result; |
|
686 } |
|
687 |
|
688 #ifdef MOZ_DUMP_PAINTING |
|
689 TemporaryRef<gfx::DataSourceSurface> |
|
690 ContentHostTexture::GetAsSurface() |
|
691 { |
|
692 if (!mTextureHost) { |
|
693 return nullptr; |
|
694 } |
|
695 |
|
696 return mTextureHost->GetAsSurface(); |
|
697 } |
|
698 |
|
699 #endif |
|
700 |
|
701 |
|
702 } // namespace |
|
703 } // namespace |