diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-06-23 21:43:52 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-06-23 21:43:52 +0000 |
commit | 9df621da5024dda2ffd77cfa6e6c0a0f68e4aa86 (patch) | |
tree | 857a1eb5abe4bd51781e49fd6bbeb9dae6fc7056 /src | |
parent | 8fd48b8bd877bf74ba787b2a60be96b6ffe96d67 (diff) |
Wrap SkStreams in IStreams instead of copying data around.
http://codereview.appspot.com/4630062/
git-svn-id: http://skia.googlecode.com/svn/trunk@1694 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/ports/SkImageDecoder_WIC.cpp | 181 | ||||
-rw-r--r-- | src/utils/win/SkAutoCoInitialize.cpp | 34 | ||||
-rw-r--r-- | src/utils/win/SkIStream.cpp | 263 |
3 files changed, 317 insertions, 161 deletions
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp index b53db3bcae..c4f1748a6f 100644 --- a/src/ports/SkImageDecoder_WIC.cpp +++ b/src/ports/SkImageDecoder_WIC.cpp @@ -1,5 +1,5 @@ /* - Copyright 2010 Google Inc. + Copyright 2011 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,137 +17,26 @@ #define WIN32_LEAN_AND_MEAN #include <Windows.h> #include <wincodec.h> +#include "SkAutoCoInitialize.h" #include "SkImageDecoder.h" #include "SkImageEncoder.h" +#include "SkIStream.h" #include "SkMovie.h" #include "SkStream.h" -#include "SkTemplates.h" - -template<typename T> -class scoped_com_ptr { -private: - T *fPtr; - - scoped_com_ptr(scoped_com_ptr const &); - scoped_com_ptr & operator=(scoped_com_ptr const &); - -public: - explicit scoped_com_ptr(T *ptr = NULL) : fPtr(ptr) { } - ~scoped_com_ptr() { - if (NULL != fPtr) { - fPtr->Release(); - fPtr = NULL; - } - } - T &operator*() const { return *fPtr; } - T *operator->() const { return fPtr; } - /** - * Returns the address of the underlying pointer. - * This is dangerous -- it breaks encapsulation and the reference escapes. - * Must only be used on instances currently pointing to NULL, - * and only to initialize the instance. - */ - T **operator&() { SkASSERT(fPtr == NULL); return &fPtr; } - T *get() const { return fPtr; } -}; - -/** - * An instance of this class initializes COM on creation - * and closes the COM library on destruction. - */ -class AutoCoInitialize : SkNoncopyable { -private: - HRESULT hr; -public: - AutoCoInitialize() : - hr( - CoInitializeEx( - NULL - , COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE - ) - ) - { } - ~AutoCoInitialize() { - if (SUCCEEDED(this->hr)) { - CoUninitialize(); - } - } - HRESULT getHR() { return this->hr; } -}; +#include "SkTScopedComPtr.h" class SkImageDecoder_WIC : public SkImageDecoder { protected: - virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); + virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode); }; -/** - * Converts a SkStream to an IStream. - * The caller must call Release() on the returned IStream. - */ -static HRESULT SkStreamToIStream(SkStream* stream, IStream** ppStream) { - //TODO(bungeman): use a real IStream wrapper - HRESULT hr = S_OK; - - size_t len = stream->getLength(); - - //Reserve memory for content of IStream. - HGLOBAL hdata = NULL; - if (SUCCEEDED(hr)) { - hdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, len); - if (NULL == hdata) { - hr = HRESULT_FROM_WIN32(GetLastError()); - } - } - - //Lock memory. - void* data = NULL; - if (SUCCEEDED(hr)) { - data = GlobalLock(hdata); - if (NULL == data) { - hr = HRESULT_FROM_WIN32(GetLastError()); - } - } - - //Write SkStream data to memory. - if (SUCCEEDED(hr)) { - size_t read = stream->read(data, len); - if (read != len) { - hr = E_FAIL; - } - } - - //Unlock memory. - if (NULL != data) { - data = NULL; - SetLastError(NO_ERROR); - GlobalUnlock(hdata); - DWORD lastError = GetLastError(); - if (SUCCEEDED(hr) && NO_ERROR != lastError) { - hr = HRESULT_FROM_WIN32(lastError); - } - } - - //Create IStream from memory. - if (SUCCEEDED(hr)) { - hr = CreateStreamOnHGlobal(hdata, TRUE, ppStream); - } - //If we failed for any reason, free the memory. - if (FAILED(hr)) { - if (NULL != hdata) { - GlobalFree(hdata); - } - } - - return hr; -} - bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { //Initialize COM. AutoCoInitialize scopedCo; HRESULT hr = scopedCo.getHR(); //Create Windows Imaging Component ImagingFactory. - scoped_com_ptr<IWICImagingFactory> piImagingFactory; + SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory @@ -158,9 +47,9 @@ bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { } //Convert SkStream to IStream. - scoped_com_ptr<IStream> piStream; + SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { - hr = SkStreamToIStream(stream, &piStream); + hr = SkIStream::CreateFromSkStream(stream, false, &piStream); } //Make sure we're at the beginning of the stream. @@ -170,7 +59,7 @@ bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { } //Create the decoder from the stream content. - scoped_com_ptr<IWICBitmapDecoder> piBitmapDecoder; + SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateDecoderFromStream( piStream.get() //Image to be decoded @@ -181,13 +70,13 @@ bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { } //Get the first frame from the decoder. - scoped_com_ptr<IWICBitmapFrameDecode> piBitmapFrameDecode; + SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; if (SUCCEEDED(hr)) { hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); } //Get the BitmapSource interface of the frame. - scoped_com_ptr<IWICBitmapSource> piBitmapSourceOriginal; + SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; if (SUCCEEDED(hr)) { hr = piBitmapFrameDecode->QueryInterface( IID_PPV_ARGS(&piBitmapSourceOriginal) @@ -213,7 +102,7 @@ bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { } //Create a format converter. - scoped_com_ptr<IWICFormatConverter> piFormatConverter; + SkTScopedComPtr<IWICFormatConverter> piFormatConverter; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); } @@ -230,7 +119,7 @@ bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { } //Get the BitmapSource interface of the format converter. - scoped_com_ptr<IWICBitmapSource> piBitmapSourceConverted; + SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; if (SUCCEEDED(hr)) { hr = piFormatConverter->QueryInterface( IID_PPV_ARGS(&piBitmapSourceConverted) @@ -300,7 +189,7 @@ bool SkImageEncoder_WIC::onEncode(SkWStream* stream HRESULT hr = scopedCo.getHR(); //Create Windows Imaging Component ImagingFactory. - scoped_com_ptr<IWICImagingFactory> piImagingFactory; + SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory @@ -310,14 +199,14 @@ bool SkImageEncoder_WIC::onEncode(SkWStream* stream ); } - //Create the stream to hold the output of the encoder. - scoped_com_ptr<IStream> piStream; + //Convert the SkWStream to an IStream. + SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { - hr = CreateStreamOnHGlobal(NULL, TRUE, &piStream); + hr = SkWIStream::CreateFromSkWStream(stream, &piStream); } //Create an encode of the appropriate type. - scoped_com_ptr<IWICBitmapEncoder> piEncoder; + SkTScopedComPtr<IWICBitmapEncoder> piEncoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder); } @@ -327,8 +216,8 @@ bool SkImageEncoder_WIC::onEncode(SkWStream* stream } //Create a the frame. - scoped_com_ptr<IWICBitmapFrameEncode> piBitmapFrameEncode; - scoped_com_ptr<IPropertyBag2> piPropertybag; + SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; + SkTScopedComPtr<IPropertyBag2> piPropertybag; if (SUCCEEDED(hr)) { hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); } @@ -389,36 +278,6 @@ bool SkImageEncoder_WIC::onEncode(SkWStream* stream hr = piEncoder->Commit(); } - //Rewind the IStream with the output of the encoder. - if (SUCCEEDED(hr)) { - LARGE_INTEGER liBeginning = { 0 }; - hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL); - } - - //Write the content of the IStream to the SkWStream. - if (SUCCEEDED(hr)) { - //TODO(bungeman): use a real IStream(SkWStream) wrapper - const unsigned int BUFFER_SIZE = 1024; - void* buffer = new BYTE[BUFFER_SIZE]; - ULONG bytesRead = 0; - while (true) { - hr = piStream->Read(buffer, BUFFER_SIZE, &bytesRead); - if (FAILED(hr)) { - break; - } - bool wrote = stream->write(buffer, bytesRead); - if (!wrote) { - hr = E_FAIL; - break; - } - if (BUFFER_SIZE != bytesRead) { - break; - } - } - stream->flush(); - delete[] buffer; - } - return SUCCEEDED(hr); } diff --git a/src/utils/win/SkAutoCoInitialize.cpp b/src/utils/win/SkAutoCoInitialize.cpp new file mode 100644 index 0000000000..7249341993 --- /dev/null +++ b/src/utils/win/SkAutoCoInitialize.cpp @@ -0,0 +1,34 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include <ole2.h> +#include "SkAutoCoInitialize.h" + +AutoCoInitialize::AutoCoInitialize() : + fHR( + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE) + ) +{ } + +AutoCoInitialize::~AutoCoInitialize() { + if (SUCCEEDED(this->fHR)) { + CoUninitialize(); + } +} + +HRESULT AutoCoInitialize::getHR() { return this->fHR; } diff --git a/src/utils/win/SkIStream.cpp b/src/utils/win/SkIStream.cpp new file mode 100644 index 0000000000..29e1c87d53 --- /dev/null +++ b/src/utils/win/SkIStream.cpp @@ -0,0 +1,263 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include <ole2.h> +#include "SkIStream.h" +#include "SkStream.h" + +/** + * SkBaseIStream + */ +SkBaseIStream::SkBaseIStream() : _refcount(1) { } +SkBaseIStream::~SkBaseIStream() { } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::QueryInterface(REFIID iid + , void ** ppvObject) +{ + if (NULL == ppvObject) { + return E_INVALIDARG; + } + if (iid == __uuidof(IUnknown) + || iid == __uuidof(IStream) + || iid == __uuidof(ISequentialStream)) + { + *ppvObject = static_cast<IStream*>(this); + AddRef(); + return S_OK; + } else { + *ppvObject = NULL; + return E_NOINTERFACE; + } +} + +ULONG STDMETHODCALLTYPE SkBaseIStream::AddRef(void) { + return (ULONG)InterlockedIncrement(&_refcount); +} + +ULONG STDMETHODCALLTYPE SkBaseIStream::Release(void) { + ULONG res = (ULONG) InterlockedDecrement(&_refcount); + if (0 == res) { + delete this; + } + return res; +} + +// ISequentialStream Interface +HRESULT STDMETHODCALLTYPE SkBaseIStream::Read(void* pv + , ULONG cb + , ULONG* pcbRead) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::Write(void const* pv + , ULONG cb + , ULONG* pcbWritten) +{ return E_NOTIMPL; } + +// IStream Interface +HRESULT STDMETHODCALLTYPE SkBaseIStream::SetSize(ULARGE_INTEGER) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::CopyTo(IStream* + , ULARGE_INTEGER + , ULARGE_INTEGER* + , ULARGE_INTEGER*) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::Commit(DWORD) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::Revert(void) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::LockRegion(ULARGE_INTEGER + , ULARGE_INTEGER + , DWORD) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::UnlockRegion(ULARGE_INTEGER + , ULARGE_INTEGER + , DWORD) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::Clone(IStream **) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove + , DWORD dwOrigin + , ULARGE_INTEGER* lpNewFilePointer) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE SkBaseIStream::Stat(STATSTG* pStatstg + , DWORD grfStatFlag) +{ return E_NOTIMPL; } + + +/** + * SkIStream + */ +SkIStream::SkIStream(SkStream* stream, bool unrefOnRelease) + : SkBaseIStream() + , fSkStream(stream) + , fUnrefOnRelease(unrefOnRelease) +{ } + +SkIStream::~SkIStream() { + if (NULL != this->fSkStream && fUnrefOnRelease) { + this->fSkStream->unref(); + } +} + +HRESULT SkIStream::CreateFromSkStream(SkStream* stream + , bool unrefOnRelease + , IStream ** ppStream) +{ + *ppStream = new SkIStream(stream, unrefOnRelease); + return S_OK; +} + +// ISequentialStream Interface +HRESULT STDMETHODCALLTYPE SkIStream::Read(void* pv, ULONG cb, ULONG* pcbRead) { + *pcbRead = this->fSkStream->read(pv, cb); + return (*pcbRead == cb) ? S_OK : S_FALSE; +} + +HRESULT STDMETHODCALLTYPE SkIStream::Write(void const* pv + , ULONG cb + , ULONG* pcbWritten) +{ + return STG_E_CANTSAVE; +} + +// IStream Interface +HRESULT STDMETHODCALLTYPE SkIStream::Seek(LARGE_INTEGER liDistanceToMove + , DWORD dwOrigin + , ULARGE_INTEGER* lpNewFilePointer) +{ + if (lpNewFilePointer != NULL) { + (*lpNewFilePointer).QuadPart = NULL; + } + + HRESULT hr = S_OK; + switch(dwOrigin) { + case STREAM_SEEK_SET: { + if (!this->fSkStream->rewind()) { + hr = E_FAIL; + } else { + size_t skipped = this->fSkStream->skip( + liDistanceToMove.QuadPart + ); + if (skipped != liDistanceToMove.QuadPart) { + hr = E_FAIL; + } + } + break; + } + case STREAM_SEEK_CUR: { + size_t skipped = this->fSkStream->skip(liDistanceToMove.QuadPart); + if (skipped != liDistanceToMove.QuadPart) { + hr = E_FAIL; + } + break; + } + case STREAM_SEEK_END: { + if (!this->fSkStream->rewind()) { + hr = E_FAIL; + } else { + size_t skipped = this->fSkStream->skip( + this->fSkStream->getLength() + liDistanceToMove.QuadPart + ); + if (skipped != liDistanceToMove.QuadPart) { + hr = E_FAIL; + } + } + break; + } + default: + hr = STG_E_INVALIDFUNCTION; + break; + } + + return hr; +} + +HRESULT STDMETHODCALLTYPE SkIStream::Stat(STATSTG* pStatstg + , DWORD grfStatFlag) +{ + if (0 == grfStatFlag & STATFLAG_NONAME) { + return STG_E_INVALIDFLAG; + } + pStatstg->pwcsName = NULL; + pStatstg->cbSize.QuadPart = this->fSkStream->getLength(); + pStatstg->clsid = CLSID_NULL; + pStatstg->type = STGTY_STREAM; + pStatstg->grfMode = STGM_READ; + return S_OK; +} + + +/** + * SkIWStream + */ +SkWIStream::SkWIStream(SkWStream* stream) + : SkBaseIStream() + , fSkWStream(stream) +{ } + +SkWIStream::~SkWIStream() { + if (NULL != this->fSkWStream) { + this->fSkWStream->flush(); + } +} + +HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream + , IStream ** ppStream) +{ + *ppStream = new SkWIStream(stream); + return S_OK; +} + +// ISequentialStream Interface +HRESULT STDMETHODCALLTYPE SkWIStream::Write(void const* pv + , ULONG cb + , ULONG* pcbWritten) +{ + HRESULT hr = S_OK; + bool wrote = this->fSkWStream->write(pv, cb); + if (wrote) { + *pcbWritten = cb; + } else { + *pcbWritten = 0; + hr = S_FALSE; + } + return hr; +} + +// IStream Interface +HRESULT STDMETHODCALLTYPE SkWIStream::Stat(STATSTG* pStatstg + , DWORD grfStatFlag) +{ + if (0 == grfStatFlag & STATFLAG_NONAME) { + return STG_E_INVALIDFLAG; + } + pStatstg->pwcsName = NULL; + pStatstg->cbSize.QuadPart = 0; + pStatstg->clsid = CLSID_NULL; + pStatstg->type = STGTY_STREAM; + pStatstg->grfMode = STGM_WRITE; + return S_OK; +} |