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 : #include "mozilla/ReentrantMonitor.h"
39 :
40 : #include "ImageLayers.h"
41 : #include "BasicLayers.h"
42 : #include "gfxImageSurface.h"
43 :
44 : #ifdef XP_MACOSX
45 : #include "gfxQuartzImageSurface.h"
46 : #endif
47 :
48 : #include "cairo.h"
49 :
50 : #include "gfxUtils.h"
51 :
52 : #include "gfxPlatform.h"
53 :
54 : using mozilla::ReentrantMonitor;
55 :
56 : namespace mozilla {
57 : namespace layers {
58 :
59 : class BasicPlanarYCbCrImage : public PlanarYCbCrImage
60 : {
61 : public:
62 0 : BasicPlanarYCbCrImage(const gfxIntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
63 : : PlanarYCbCrImage(aRecycleBin)
64 0 : , mScaleHint(aScaleHint)
65 : {
66 0 : SetOffscreenFormat(aOffscreenFormat);
67 0 : }
68 :
69 0 : ~BasicPlanarYCbCrImage()
70 0 : {
71 0 : if (mDecodedBuffer) {
72 : // Right now this only happens if the Image was never drawn, otherwise
73 : // this will have been tossed away at surface destruction.
74 0 : mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
75 : }
76 0 : }
77 :
78 : virtual void SetData(const Data& aData);
79 : already_AddRefed<gfxASurface> GetAsSurface();
80 :
81 : private:
82 : gfxIntSize mScaleHint;
83 : int mStride;
84 : nsAutoArrayPtr<PRUint8> mDecodedBuffer;
85 : };
86 :
87 : class BasicImageFactory : public ImageFactory
88 0 : {
89 : public:
90 0 : BasicImageFactory() {}
91 :
92 0 : virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
93 : PRUint32 aNumFormats,
94 : const gfxIntSize &aScaleHint,
95 : BufferRecycleBin *aRecycleBin)
96 : {
97 0 : if (!aNumFormats) {
98 0 : return nsnull;
99 : }
100 :
101 0 : nsRefPtr<Image> image;
102 0 : if (aFormats[0] == Image::PLANAR_YCBCR) {
103 0 : image = new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin);
104 0 : return image.forget();
105 : }
106 :
107 0 : return ImageFactory::CreateImage(aFormats, aNumFormats, aScaleHint, aRecycleBin);
108 : }
109 : };
110 :
111 : void
112 0 : BasicPlanarYCbCrImage::SetData(const Data& aData)
113 : {
114 0 : PlanarYCbCrImage::SetData(aData);
115 :
116 : // Do some sanity checks to prevent integer overflow
117 0 : if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
118 : aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
119 0 : NS_ERROR("Illegal image source width or height");
120 0 : return;
121 : }
122 :
123 0 : gfxASurface::gfxImageFormat format = GetOffscreenFormat();
124 :
125 0 : gfxIntSize size(mScaleHint);
126 0 : gfxUtils::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
127 0 : if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
128 : size.height > PlanarYCbCrImage::MAX_DIMENSION) {
129 0 : NS_ERROR("Illegal image dest width or height");
130 0 : return;
131 : }
132 :
133 0 : mStride = gfxASurface::FormatStrideForWidth(format, size.width);
134 0 : mDecodedBuffer = AllocateBuffer(size.height * mStride);
135 0 : if (!mDecodedBuffer) {
136 : // out of memory
137 0 : return;
138 : }
139 :
140 0 : gfxUtils::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride);
141 0 : SetOffscreenFormat(format);
142 0 : mSize = size;
143 : }
144 :
145 : static cairo_user_data_key_t imageSurfaceDataKey;
146 :
147 : static void
148 0 : DestroyBuffer(void* aBuffer)
149 : {
150 0 : delete[] static_cast<PRUint8*>(aBuffer);
151 0 : }
152 :
153 : already_AddRefed<gfxASurface>
154 0 : BasicPlanarYCbCrImage::GetAsSurface()
155 : {
156 0 : NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
157 :
158 0 : if (mSurface) {
159 0 : nsRefPtr<gfxASurface> result = mSurface.get();
160 0 : return result.forget();
161 : }
162 :
163 0 : if (!mDecodedBuffer) {
164 0 : return PlanarYCbCrImage::GetAsSurface();
165 : }
166 :
167 0 : gfxASurface::gfxImageFormat format = GetOffscreenFormat();
168 :
169 : nsRefPtr<gfxImageSurface> imgSurface =
170 0 : new gfxImageSurface(mDecodedBuffer, mSize, mStride, format);
171 0 : if (!imgSurface || imgSurface->CairoStatus() != 0) {
172 0 : return nsnull;
173 : }
174 :
175 : // Pass ownership of the buffer to the surface
176 0 : imgSurface->SetData(&imageSurfaceDataKey, mDecodedBuffer.forget(), DestroyBuffer);
177 :
178 0 : nsRefPtr<gfxASurface> result = imgSurface.get();
179 : #if defined(XP_MACOSX)
180 : nsRefPtr<gfxQuartzImageSurface> quartzSurface =
181 : new gfxQuartzImageSurface(imgSurface);
182 : if (quartzSurface) {
183 : result = quartzSurface.forget();
184 : }
185 : #endif
186 :
187 0 : mSurface = result;
188 :
189 0 : return result.forget();
190 : }
191 :
192 : ImageFactory*
193 0 : BasicLayerManager::GetImageFactory()
194 : {
195 0 : if (!mFactory) {
196 0 : mFactory = new BasicImageFactory();
197 : }
198 :
199 0 : return mFactory.get();
200 : }
201 :
202 : }
203 : }
|