1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Robert O'Callahan <robert@ocallahan.org>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef GFX_IMAGELAYER_H
39 : #define GFX_IMAGELAYER_H
40 :
41 : #include "Layers.h"
42 :
43 : #include "nsISupportsImpl.h"
44 : #include "gfxPattern.h"
45 : #include "nsThreadUtils.h"
46 : #include "mozilla/ReentrantMonitor.h"
47 : #include "mozilla/TimeStamp.h"
48 : #include "mozilla/mozalloc.h"
49 : #include "mozilla/Mutex.h"
50 : #include "gfxPlatform.h"
51 :
52 : #ifdef XP_MACOSX
53 : #include "nsIOSurface.h"
54 : #endif
55 :
56 : namespace mozilla {
57 :
58 : class CrossProcessMutex;
59 : namespace ipc {
60 : class Shmem;
61 : }
62 :
63 : namespace layers {
64 :
65 : enum StereoMode {
66 : STEREO_MODE_MONO,
67 : STEREO_MODE_LEFT_RIGHT,
68 : STEREO_MODE_RIGHT_LEFT,
69 : STEREO_MODE_BOTTOM_TOP,
70 : STEREO_MODE_TOP_BOTTOM
71 : };
72 :
73 : struct ImageBackendData
74 : {
75 : virtual ~ImageBackendData() {}
76 :
77 : protected:
78 : ImageBackendData() {}
79 : };
80 :
81 : /**
82 : * A class representing a buffer of pixel data. The data can be in one
83 : * of various formats including YCbCr.
84 : *
85 : * Create an image using an ImageContainer. Fill the image with data, and
86 : * then call ImageContainer::SetImage to display it. An image must not be
87 : * modified after calling SetImage. Image implementations do not need to
88 : * perform locking; when filling an Image, the Image client is responsible
89 : * for ensuring only one thread accesses the Image at a time, and after
90 : * SetImage the image is immutable.
91 : *
92 : * When resampling an Image, only pixels within the buffer should be
93 : * sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
94 : */
95 : class THEBES_API Image {
96 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
97 :
98 : public:
99 : virtual ~Image() {}
100 :
101 : enum Format {
102 : /**
103 : * The PLANAR_YCBCR format creates a PlanarYCbCrImage. All backends should
104 : * support this format, because the Ogg video decoder depends on it.
105 : * The maximum image width and height is 16384.
106 : */
107 : PLANAR_YCBCR,
108 :
109 : /**
110 : * The CAIRO_SURFACE format creates a CairoImage. All backends should
111 : * support this format, because video rendering sometimes requires it.
112 : *
113 : * This format is useful even though a ThebesLayer could be used.
114 : * It makes it easy to render a cairo surface when another Image format
115 : * could be used. It can also avoid copying the surface data in some
116 : * cases.
117 : *
118 : * Images in CAIRO_SURFACE format should only be created and
119 : * manipulated on the main thread, since the underlying cairo surface
120 : * is main-thread-only.
121 : */
122 : CAIRO_SURFACE,
123 :
124 : /**
125 : * The MAC_IO_SURFACE format creates a MacIOSurfaceImage.
126 : *
127 : * It wraps an IOSurface object and binds it directly to a GL texture.
128 : */
129 : MAC_IO_SURFACE,
130 :
131 : /**
132 : * An bitmap image that can be shared with a remote process.
133 : */
134 : REMOTE_IMAGE_BITMAP
135 : };
136 :
137 0 : Format GetFormat() { return mFormat; }
138 : void* GetImplData() { return mImplData; }
139 :
140 : virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
141 : virtual gfxIntSize GetSize() = 0;
142 :
143 : ImageBackendData* GetBackendData(LayerManager::LayersBackend aBackend)
144 : { return mBackendData[aBackend]; }
145 : void SetBackendData(LayerManager::LayersBackend aBackend, ImageBackendData* aData)
146 : { mBackendData[aBackend] = aData; }
147 :
148 : protected:
149 : Image(void* aImplData, Format aFormat) :
150 : mImplData(aImplData),
151 : mFormat(aFormat)
152 : {}
153 :
154 : nsAutoPtr<ImageBackendData> mBackendData[LayerManager::LAYERS_LAST];
155 :
156 : void* mImplData;
157 : Format mFormat;
158 : };
159 :
160 : /**
161 : * A RecycleBin is owned by an ImageContainer. We store buffers in it that we
162 : * want to recycle from one image to the next.It's a separate object from
163 : * ImageContainer because images need to store a strong ref to their RecycleBin
164 : * and we must avoid creating a reference loop between an ImageContainer and
165 : * its active image.
166 : */
167 : class BufferRecycleBin {
168 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
169 :
170 : typedef mozilla::gl::GLContext GLContext;
171 :
172 : public:
173 : BufferRecycleBin();
174 :
175 : void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize);
176 : // Returns a recycled buffer of the right size, or allocates a new buffer.
177 : PRUint8* GetBuffer(PRUint32 aSize);
178 :
179 : private:
180 : typedef mozilla::Mutex Mutex;
181 :
182 : // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
183 : // and mRecycledTextureSizes
184 : Mutex mLock;
185 :
186 : // We should probably do something to prune this list on a timer so we don't
187 : // eat excess memory while video is paused...
188 : nsTArray<nsAutoArrayPtr<PRUint8> > mRecycledBuffers;
189 : // This is only valid if mRecycledBuffers is non-empty
190 : PRUint32 mRecycledBufferSize;
191 : };
192 :
193 : /**
194 : * Returns true if aFormat is in the given format array.
195 : */
196 : static inline bool
197 : FormatInList(const Image::Format* aFormats, PRUint32 aNumFormats,
198 : Image::Format aFormat)
199 : {
200 : for (PRUint32 i = 0; i < aNumFormats; ++i) {
201 : if (aFormats[i] == aFormat) {
202 : return true;
203 : }
204 : }
205 : return false;
206 : }
207 :
208 : class CompositionNotifySink
209 0 : {
210 : public:
211 : virtual void DidComposite() = 0;
212 : };
213 :
214 : /**
215 : * A class that manages Image creation for a LayerManager. The only reason
216 : * we need a separate class here is that LayerMananers aren't threadsafe
217 : * (because layers can only be used on the main thread) and we want to
218 : * be able to create images from any thread, to facilitate video playback
219 : * without involving the main thread, for example.
220 : * Different layer managers can implement child classes of this making it
221 : * possible to create layer manager specific images.
222 : * This class is not meant to be used directly but rather can be set on an
223 : * image container. This is usually done by the layer system internally and
224 : * not explicitly by users. For PlanarYCbCr or Cairo images the default
225 : * implementation will creates images whose data lives in system memory, for
226 : * MacIOSurfaces the default implementation will be a simple nsIOSurface
227 : * wrapper.
228 : */
229 :
230 : class THEBES_API ImageFactory
231 : {
232 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
233 : protected:
234 : friend class ImageContainer;
235 :
236 : ImageFactory() {}
237 : virtual ~ImageFactory() {}
238 :
239 : virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
240 : PRUint32 aNumFormats,
241 : const gfxIntSize &aScaleHint,
242 : BufferRecycleBin *aRecycleBin);
243 :
244 : };
245 :
246 : /**
247 : * This struct is used to store RemoteImages, it is meant to be able to live in
248 : * shared memory. Therefor it should not contain a vtable pointer. Remote
249 : * users can manipulate the data in this structure to specify what image is to
250 : * be drawn by the container. When accessing this data users should make sure
251 : * the mutex synchronizing access to the structure is held!
252 : */
253 : struct RemoteImageData {
254 : enum Type {
255 : /**
256 : * This is a format that uses raw bitmap data.
257 : */
258 : RAW_BITMAP
259 : };
260 : /* These formats describe the format in the memory byte-order */
261 : enum Format {
262 : /* 8 bits per channel */
263 : BGRA32,
264 : /* 8 bits per channel, alpha channel is ignored */
265 : BGRX32
266 : };
267 :
268 : // This should be set to true if a change was made so that the ImageContainer
269 : // knows to throw out any cached RemoteImage objects.
270 : bool mWasUpdated;
271 : Type mType;
272 : Format mFormat;
273 : gfxIntSize mSize;
274 : union {
275 : struct {
276 : /* This pointer is set by a remote process, however it will be set to
277 : * the container process' address the memory of the raw bitmap resides
278 : * at.
279 : */
280 : unsigned char *mData;
281 : int mStride;
282 : } mBitmap;
283 : };
284 : };
285 :
286 : /**
287 : * A class that manages Images for an ImageLayer. The only reason
288 : * we need a separate class here is that ImageLayers aren't threadsafe
289 : * (because layers can only be used on the main thread) and we want to
290 : * be able to set the current Image from any thread, to facilitate
291 : * video playback without involving the main thread, for example.
292 : */
293 : class THEBES_API ImageContainer {
294 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
295 :
296 : public:
297 : ImageContainer() :
298 : mReentrantMonitor("ImageContainer.mReentrantMonitor"),
299 : mPaintCount(0),
300 : mPreviousImagePainted(false),
301 : mImageFactory(new ImageFactory()),
302 : mRecycleBin(new BufferRecycleBin()),
303 : mRemoteData(nsnull),
304 : mRemoteDataMutex(nsnull),
305 : mCompositionNotifySink(nsnull)
306 : {}
307 :
308 : ~ImageContainer();
309 :
310 : /**
311 : * Create an Image in one of the given formats.
312 : * Picks the "best" format from the list and creates an Image of that
313 : * format.
314 : * Returns null if this backend does not support any of the formats.
315 : * Can be called on any thread. This method takes mReentrantMonitor
316 : * when accessing thread-shared state.
317 : */
318 : already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
319 : PRUint32 aNumFormats);
320 :
321 : /**
322 : * Set an Image as the current image to display. The Image must have
323 : * been created by this ImageContainer.
324 : * Can be called on any thread. This method takes mReentrantMonitor
325 : * when accessing thread-shared state.
326 : * aImage can be null. While it's null, nothing will be painted.
327 : *
328 : * The Image data must not be modified after this method is called!
329 : *
330 : * Implementations must call CurrentImageChanged() while holding
331 : * mReentrantMonitor.
332 : */
333 : void SetCurrentImage(Image* aImage);
334 :
335 : /**
336 : * Returns if the container currently has an image.
337 : * Can be called on any thread. This method takes mReentrantMonitor
338 : * when accessing thread-shared state.
339 : */
340 : bool HasCurrentImage();
341 :
342 : /**
343 : * Lock the current Image.
344 : * This has to add a reference since otherwise there are race conditions
345 : * where the current image is destroyed before the caller can add
346 : * a reference. This lock strictly guarantees the underlying image remains
347 : * valid, it does not mean the current image cannot change.
348 : * Can be called on any thread. This method will lock the cross-process
349 : * mutex to ensure remote processes cannot alter underlying data. This call
350 : * -must- be balanced by a call to UnlockCurrentImage and users should avoid
351 : * holding the image locked for a long time.
352 : */
353 : already_AddRefed<Image> LockCurrentImage();
354 :
355 : /**
356 : * This call unlocks the image. For remote images releasing the cross-process
357 : * mutex.
358 : */
359 : void UnlockCurrentImage();
360 :
361 : /**
362 : * Get the current image as a gfxASurface. This is useful for fallback
363 : * rendering.
364 : * This can only be called from the main thread, since cairo objects
365 : * can only be used from the main thread.
366 : * This is defined here and not on Image because it's possible (likely)
367 : * that some backends will make an Image "ready to draw" only when it
368 : * becomes the current image for an image container.
369 : * Returns null if there is no current image.
370 : * Returns the size in aSize.
371 : * The returned surface will never be modified. The caller must not
372 : * modify it.
373 : * Can be called on any thread. This method takes mReentrantMonitor
374 : * when accessing thread-shared state.
375 : * If the current image is a remote image, that is, if it is an image that
376 : * may be shared accross processes, calling this function will make
377 : * a copy of the image data while holding the mRemoteDataMutex. If possible,
378 : * the lock methods should be used to avoid the copy, however this should be
379 : * avoided if the surface is required for a long period of time.
380 : */
381 : already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
382 :
383 : /**
384 : * This is similar to GetCurrentAsSurface, however this does not make a copy
385 : * of the image data and requires the user to call UnlockCurrentImage when
386 : * done with the image data. Once UnlockCurrentImage has been called the
387 : * surface returned by this function is no longer valid! This works for any
388 : * type of image. Optionally a pointer can be passed to receive the current
389 : * image.
390 : */
391 : already_AddRefed<gfxASurface> LockCurrentAsSurface(gfxIntSize* aSizeResult,
392 : Image** aCurrentImage = nsnull);
393 :
394 : /**
395 : * Returns the size of the image in pixels.
396 : * Can be called on any thread. This method takes mReentrantMonitor when accessing
397 : * thread-shared state.
398 : */
399 : gfxIntSize GetCurrentSize();
400 :
401 : /**
402 : * Sets a size that the image is expected to be rendered at.
403 : * This is a hint for image backends to optimize scaling.
404 : * Default implementation in this class is to ignore the hint.
405 : * Can be called on any thread. This method takes mReentrantMonitor
406 : * when accessing thread-shared state.
407 : */
408 0 : void SetScaleHint(const gfxIntSize& aScaleHint)
409 0 : { mScaleHint = aScaleHint; }
410 :
411 : void SetImageFactory(ImageFactory *aFactory)
412 : {
413 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
414 : mImageFactory = aFactory ? aFactory : new ImageFactory();
415 : }
416 :
417 : /**
418 : * Returns the time at which the currently contained image was first
419 : * painted. This is reset every time a new image is set as the current
420 : * image. Note this may return a null timestamp if the current image
421 : * has not yet been painted. Can be called from any thread.
422 : */
423 0 : TimeStamp GetPaintTime() {
424 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
425 0 : return mPaintTime;
426 : }
427 :
428 : /**
429 : * Returns the number of images which have been contained in this container
430 : * and painted at least once. Can be called from any thread.
431 : */
432 0 : PRUint32 GetPaintCount() {
433 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
434 0 : return mPaintCount;
435 : }
436 :
437 : /**
438 : * Increments mPaintCount if this is the first time aPainted has been
439 : * painted, and sets mPaintTime if the painted image is the current image.
440 : * current image. Can be called from any thread.
441 : */
442 : void NotifyPaintedImage(Image* aPainted) {
443 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
444 :
445 : nsRefPtr<Image> current = mActiveImage;
446 : if (aPainted == current) {
447 : if (mPaintTime.IsNull()) {
448 : mPaintTime = TimeStamp::Now();
449 : mPaintCount++;
450 : }
451 : } else if (!mPreviousImagePainted) {
452 : // While we were painting this image, the current image changed. We
453 : // still must count it as painted, but can't set mPaintTime, since we're
454 : // no longer the current image.
455 : mPaintCount++;
456 : mPreviousImagePainted = true;
457 : }
458 :
459 : if (mCompositionNotifySink) {
460 : mCompositionNotifySink->DidComposite();
461 : }
462 : }
463 :
464 0 : void SetCompositionNotifySink(CompositionNotifySink *aSink) {
465 0 : mCompositionNotifySink = aSink;
466 0 : }
467 :
468 : /**
469 : * This function is called to tell the ImageContainer where the
470 : * (cross-process) segment lives where the shared data about possible
471 : * remote images are stored. In addition to this a CrossProcessMutex object
472 : * is passed telling the container how to synchronize access to this data.
473 : * NOTE: This should be called during setup of the container and not after
474 : * usage has started.
475 : */
476 : void SetRemoteImageData(RemoteImageData *aRemoteData,
477 : CrossProcessMutex *aRemoteDataMutex);
478 : /**
479 : * This can be used to check if the container has RemoteData set.
480 : */
481 : RemoteImageData *GetRemoteImageData() { return mRemoteData; }
482 :
483 : protected:
484 : typedef mozilla::ReentrantMonitor ReentrantMonitor;
485 :
486 : // This is called to ensure we have an active image, this may not be true
487 : // when we're storing image information in a RemoteImageData structure.
488 : // NOTE: If we have remote data mRemoteDataMutex should be locked when
489 : // calling this function!
490 : void EnsureActiveImage();
491 :
492 : // ReentrantMonitor to protect thread safe access to the "current
493 : // image", and any other state which is shared between threads.
494 : ReentrantMonitor mReentrantMonitor;
495 :
496 : // Performs necessary housekeeping to ensure the painted frame statistics
497 : // are accurate. Must be called by SetCurrentImage() implementations with
498 : // mReentrantMonitor held.
499 : void CurrentImageChanged() {
500 : mReentrantMonitor.AssertCurrentThreadIn();
501 : mPreviousImagePainted = !mPaintTime.IsNull();
502 : mPaintTime = TimeStamp();
503 : }
504 :
505 : nsRefPtr<Image> mActiveImage;
506 :
507 : // Number of contained images that have been painted at least once. It's up
508 : // to the ImageContainer implementation to ensure accesses to this are
509 : // threadsafe.
510 : PRUint32 mPaintCount;
511 :
512 : // Time stamp at which the current image was first painted. It's up to the
513 : // ImageContainer implementation to ensure accesses to this are threadsafe.
514 : TimeStamp mPaintTime;
515 :
516 : // Denotes whether the previous image was painted.
517 : bool mPreviousImagePainted;
518 :
519 : // This is the image factory used by this container, layer managers using
520 : // this container can set an alternative image factory that will be used to
521 : // create images for this container.
522 : nsRefPtr<ImageFactory> mImageFactory;
523 :
524 : gfxIntSize mScaleHint;
525 :
526 : nsRefPtr<BufferRecycleBin> mRecycleBin;
527 :
528 : // This contains the remote image data for this container, if this is NULL
529 : // that means the container has no other process that may control its active
530 : // image.
531 : RemoteImageData *mRemoteData;
532 :
533 : // This cross-process mutex is used to synchronise access to mRemoteData.
534 : // When this mutex is held, we will always be inside the mReentrantMonitor
535 : // however the same is not true vice versa.
536 : CrossProcessMutex *mRemoteDataMutex;
537 :
538 : CompositionNotifySink *mCompositionNotifySink;
539 : };
540 :
541 : class AutoLockImage
542 : {
543 : public:
544 : AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
545 : AutoLockImage(ImageContainer *aContainer, gfxASurface **aSurface) : mContainer(aContainer) {
546 : *aSurface = mContainer->LockCurrentAsSurface(&mSize, getter_AddRefs(mImage)).get();
547 : }
548 : ~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
549 :
550 : Image* GetImage() { return mImage; }
551 : const gfxIntSize &GetSize() { return mSize; }
552 :
553 : void Unlock() {
554 : if (mContainer) {
555 : mImage = nsnull;
556 : mContainer->UnlockCurrentImage();
557 : mContainer = nsnull;
558 : }
559 : }
560 :
561 : /** Things get a little tricky here, because our underlying image can -still-
562 : * change, and OS X requires a complicated callback mechanism to update this
563 : * we need to support staying the lock and getting the new image in a proper
564 : * way. This method makes any images retrieved with GetImage invalid!
565 : */
566 : void Refresh() {
567 : if (mContainer) {
568 : mContainer->UnlockCurrentImage();
569 : mImage = mContainer->LockCurrentImage();
570 : }
571 : }
572 :
573 : private:
574 : ImageContainer *mContainer;
575 : nsRefPtr<Image> mImage;
576 : gfxIntSize mSize;
577 : };
578 :
579 : /**
580 : * A Layer which renders an Image.
581 : */
582 : class THEBES_API ImageLayer : public Layer {
583 : public:
584 : enum ScaleMode {
585 : SCALE_NONE,
586 : SCALE_STRETCH // Unimplemented on GL layers and e10s
587 : // Unimplemented - SCALE_PRESERVE_ASPECT_RATIO_CONTAIN
588 : };
589 :
590 : /**
591 : * CONSTRUCTION PHASE ONLY
592 : * Set the ImageContainer. aContainer must have the same layer manager
593 : * as this layer.
594 : */
595 0 : void SetContainer(ImageContainer* aContainer)
596 : {
597 0 : mContainer = aContainer;
598 0 : }
599 : /**
600 : * CONSTRUCTION PHASE ONLY
601 : * Set the filter used to resample this image if necessary.
602 : */
603 0 : void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
604 :
605 : /**
606 : * CONSTRUCTION PHASE ONLY
607 : * Set the size to scale the image to and the mode at which to scale.
608 : */
609 0 : void SetScaleToSize(const gfxIntSize &aSize, ScaleMode aMode)
610 : {
611 0 : mScaleToSize = aSize;
612 0 : mScaleMode = aMode;
613 0 : }
614 :
615 :
616 : ImageContainer* GetContainer() { return mContainer; }
617 : gfxPattern::GraphicsFilter GetFilter() { return mFilter; }
618 :
619 : MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE)
620 :
621 : virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
622 : {
623 : // Snap image edges to pixel boundaries
624 : gfxRect snap(0, 0, 0, 0);
625 : if (mContainer) {
626 : gfxIntSize size = mContainer->GetCurrentSize();
627 : snap.SizeTo(gfxSize(size.width, size.height));
628 : }
629 : // Snap our local transform first, and snap the inherited transform as well.
630 : // This makes our snapping equivalent to what would happen if our content
631 : // was drawn into a ThebesLayer (gfxContext would snap using the local
632 : // transform, then we'd snap again when compositing the ThebesLayer).
633 : mEffectiveTransform =
634 : SnapTransform(GetLocalTransform(), snap, nsnull)*
635 : SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nsnull);
636 : }
637 :
638 : protected:
639 : ImageLayer(LayerManager* aManager, void* aImplData)
640 : : Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD)
641 : , mScaleMode(SCALE_NONE) {}
642 :
643 : virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
644 :
645 :
646 : nsRefPtr<ImageContainer> mContainer;
647 : gfxPattern::GraphicsFilter mFilter;
648 : gfxIntSize mScaleToSize;
649 : ScaleMode mScaleMode;
650 : };
651 :
652 : /****** Image subtypes for the different formats ******/
653 :
654 : /**
655 : * We assume that the image data is in the REC 470M color space (see
656 : * Theora specification, section 4.3.1).
657 : *
658 : * The YCbCr format can be:
659 : *
660 : * 4:4:4 - CbCr width/height are the same as Y.
661 : * 4:2:2 - CbCr width is half that of Y. Height is the same.
662 : * 4:2:0 - CbCr width and height is half that of Y.
663 : *
664 : * The color format is detected based on the height/width ratios
665 : * defined above.
666 : *
667 : * The Image that is rendered is the picture region defined by
668 : * mPicX, mPicY and mPicSize. The size of the rendered image is
669 : * mPicSize, not mYSize or mCbCrSize.
670 : */
671 : class THEBES_API PlanarYCbCrImage : public Image {
672 : public:
673 0 : struct Data {
674 : // Luminance buffer
675 : PRUint8* mYChannel;
676 : PRInt32 mYStride;
677 : gfxIntSize mYSize;
678 : // Chroma buffers
679 : PRUint8* mCbChannel;
680 : PRUint8* mCrChannel;
681 : PRInt32 mCbCrStride;
682 : gfxIntSize mCbCrSize;
683 : // Picture region
684 : PRUint32 mPicX;
685 : PRUint32 mPicY;
686 : gfxIntSize mPicSize;
687 : StereoMode mStereoMode;
688 :
689 : nsIntRect GetPictureRect() const {
690 : return nsIntRect(mPicX, mPicY,
691 : mPicSize.width,
692 : mPicSize.height);
693 : }
694 : };
695 :
696 : enum {
697 : MAX_DIMENSION = 16384
698 : };
699 :
700 : ~PlanarYCbCrImage();
701 :
702 : /**
703 : * This makes a copy of the data buffers, in order to support functioning
704 : * in all different layer managers.
705 : */
706 : virtual void SetData(const Data& aData);
707 :
708 : /**
709 : * Ask this Image to not convert YUV to RGB during SetData, and make
710 : * the original data available through GetData. This is optional,
711 : * and not all PlanarYCbCrImages will support it.
712 : */
713 : virtual void SetDelayedConversion(bool aDelayed) { }
714 :
715 : /**
716 : * Grab the original YUV data. This is optional.
717 : */
718 : virtual const Data* GetData() { return &mData; }
719 :
720 : /**
721 : * Make a copy of the YCbCr data into local storage.
722 : *
723 : * @param aData Input image data.
724 : */
725 : void CopyData(const Data& aData);
726 :
727 : /**
728 : * Return a buffer to store image data in.
729 : * The default implementation returns memory that can
730 : * be freed wit delete[]
731 : */
732 : virtual PRUint8* AllocateBuffer(PRUint32 aSize);
733 :
734 : /**
735 : * Return the number of bytes of heap memory used to store this image.
736 : */
737 : virtual PRUint32 GetDataSize() { return mBufferSize; }
738 :
739 : already_AddRefed<gfxASurface> GetAsSurface();
740 :
741 : virtual gfxIntSize GetSize() { return mSize; }
742 :
743 : void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
744 : gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
745 :
746 : // XXX - not easy to protect these sadly.
747 : nsAutoArrayPtr<PRUint8> mBuffer;
748 : PRUint32 mBufferSize;
749 : Data mData;
750 : gfxIntSize mSize;
751 : gfxImageFormat mOffscreenFormat;
752 : nsCountedRef<nsMainThreadSurfaceRef> mSurface;
753 : nsRefPtr<BufferRecycleBin> mRecycleBin;
754 :
755 : PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
756 : };
757 :
758 : /**
759 : * Currently, the data in a CairoImage surface is treated as being in the
760 : * device output color space. This class is very simple as all backends
761 : * have to know about how to deal with drawing a cairo image.
762 : */
763 : class THEBES_API CairoImage : public Image {
764 : public:
765 0 : struct Data {
766 : gfxASurface* mSurface;
767 : gfxIntSize mSize;
768 : };
769 :
770 : /**
771 : * This can only be called on the main thread. It may add a reference
772 : * to the surface (which will eventually be released on the main thread).
773 : * The surface must not be modified after this call!!!
774 : */
775 0 : void SetData(const Data& aData)
776 : {
777 0 : mSurface = aData.mSurface;
778 0 : mSize = aData.mSize;
779 0 : }
780 :
781 :
782 : virtual already_AddRefed<gfxASurface> GetAsSurface()
783 : {
784 : NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
785 : nsRefPtr<gfxASurface> surface = mSurface.get();
786 : return surface.forget();
787 : }
788 :
789 : gfxIntSize GetSize() { return mSize; }
790 :
791 : CairoImage() : Image(NULL, CAIRO_SURFACE) {}
792 :
793 : nsCountedRef<nsMainThreadSurfaceRef> mSurface;
794 : gfxIntSize mSize;
795 : };
796 :
797 : #ifdef XP_MACOSX
798 : class THEBES_API MacIOSurfaceImage : public Image {
799 : public:
800 : struct Data {
801 : nsIOSurface* mIOSurface;
802 : };
803 :
804 : MacIOSurfaceImage()
805 : : Image(NULL, MAC_IO_SURFACE)
806 : , mSize(0, 0)
807 : , mPluginInstanceOwner(NULL)
808 : , mUpdateCallback(NULL)
809 : , mDestroyCallback(NULL)
810 : {}
811 :
812 : virtual ~MacIOSurfaceImage()
813 : {
814 : if (mDestroyCallback) {
815 : mDestroyCallback(mPluginInstanceOwner);
816 : }
817 : }
818 :
819 : /**
820 : * This can only be called on the main thread. It may add a reference
821 : * to the surface (which will eventually be released on the main thread).
822 : * The surface must not be modified after this call!!!
823 : */
824 : virtual void SetData(const Data& aData);
825 :
826 : /**
827 : * Temporary hacks to force plugin drawing during an empty transaction.
828 : * This should not be used for anything else, and will be removed
829 : * when async plugin rendering is complete.
830 : */
831 : typedef void (*UpdateSurfaceCallback)(ImageContainer* aContainer, void* aInstanceOwner);
832 : virtual void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner)
833 : {
834 : mUpdateCallback = aCallback;
835 : mPluginInstanceOwner = aInstanceOwner;
836 : }
837 :
838 : typedef void (*DestroyCallback)(void* aInstanceOwner);
839 : virtual void SetDestroyCallback(DestroyCallback aCallback)
840 : {
841 : mDestroyCallback = aCallback;
842 : }
843 :
844 : virtual gfxIntSize GetSize()
845 : {
846 : return mSize;
847 : }
848 :
849 : nsIOSurface* GetIOSurface()
850 : {
851 : return mIOSurface;
852 : }
853 :
854 : void Update(ImageContainer* aContainer);
855 :
856 : virtual already_AddRefed<gfxASurface> GetAsSurface();
857 :
858 : private:
859 : gfxIntSize mSize;
860 : nsRefPtr<nsIOSurface> mIOSurface;
861 : void* mPluginInstanceOwner;
862 : UpdateSurfaceCallback mUpdateCallback;
863 : DestroyCallback mDestroyCallback;
864 : };
865 : #endif
866 :
867 : class RemoteBitmapImage : public Image {
868 : public:
869 : RemoteBitmapImage() : Image(NULL, REMOTE_IMAGE_BITMAP) {}
870 :
871 : already_AddRefed<gfxASurface> GetAsSurface();
872 :
873 : gfxIntSize GetSize() { return mSize; }
874 :
875 : unsigned char *mData;
876 : int mStride;
877 : gfxIntSize mSize;
878 : RemoteImageData::Format mFormat;
879 : };
880 :
881 : }
882 : }
883 :
884 : #endif /* GFX_IMAGELAYER_H */
|