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
diff --git a/gyp/images.gyp b/gyp/images.gyp
index 8f0a06b..dad4361 100644
--- a/gyp/images.gyp
+++ b/gyp/images.gyp
@@ -6,6 +6,9 @@
{
'target_name': 'images',
'type': 'static_library',
+ 'dependencies': [
+ 'utils.gyp:utils',
+ ],
'include_dirs': [
'../include/config',
'../include/core',
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index 8845d9a..9a3683f 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -12,6 +12,7 @@
'../include/utils',
'../include/utils/mac',
'../include/utils/unix',
+ '../include/utils/win',
'../include/views',
'../include/effects',
'../include/xml',
@@ -59,22 +60,32 @@
'../src/utils/SkSfntUtils.cpp',
'../src/utils/SkUnitMappers.cpp',
+ #mac
'../include/utils/mac/SkCGUtils.h',
'../src/utils/mac/SkCreateCGImageRef.cpp',
'../src/utils/mac/SkEGLContext_mac.cpp',
'../src/utils/mac/skia_mac.cpp',
'../src/utils/mac/SkOSWindow_Mac.cpp',
+ #mesa
'../src/utils/mesa/SkEGLContext_Mesa.cpp',
+ #sdl
'../src/utils/SDL/SkOSWindow_SDL.cpp',
+ #*nix
'../src/utils/unix/keysym2ucs.c',
'../src/utils/unix/SkEGLContext_Unix.cpp',
'../src/utils/unix/SkOSWindow_Unix.cpp',
+ #windows
+ '../include/utils/win/SkAutoCoInitialize.h',
+ '../include/utils/win/SkIStream.h',
+ '../include/utils/win/SkTScopedComPtr.h',
+ '../src/utils/win/SkAutoCoInitialize.cpp',
'../src/utils/win/skia_win.cpp',
'../src/utils/win/SkEGLContext_Win.cpp',
+ '../src/utils/win/SkIStream.cpp',
'../src/utils/win/SkOSWindow_Win.cpp',
],
'sources!': [
@@ -82,18 +93,6 @@
'../src/utils/SDL/SkOSWindow_SDL.cpp',
],
'conditions': [
- [ 'OS != "mac"', {
- 'sources!': [
- '../include/utils/mac/SkCGUtils.h',
- '../src/utils/mac/SkCreateCGImageRef.cpp',
- '../src/utils/mac/SkEGLContext_mac.cpp',
- '../src/utils/mac/skia_mac.cpp',
- '../src/utils/mac/SkOSWindow_Mac.cpp',
- ],
- 'include_dirs!': [
- '../include/utils/mac',
- ],
- }],
[ 'OS == "mac"', {
'sources!': [
'../src/utils/SkEGLContext_none.cpp',
@@ -103,18 +102,19 @@
'$(SDKROOT)/System/Library/Frameworks/AGL.framework',
],
},
- }],
- [ 'OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris"', {
- 'sources!': [
- '../src/utils/unix/keysym2ucs.c',
- '../src/utils/unix/SkEGLContext_Unix.cpp',
- '../src/utils/unix/SkOSWindow_Unix.cpp',
- ],
+ },{ #else if 'OS != "mac"'
'include_dirs!': [
- '../include/utils/unix',
+ '../include/utils/mac',
+ ],
+ 'sources!': [
+ '../include/utils/mac/SkCGUtils.h',
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+ '../src/utils/mac/SkEGLContext_mac.cpp',
+ '../src/utils/mac/skia_mac.cpp',
+ '../src/utils/mac/SkOSWindow_Mac.cpp',
],
}],
- [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
+ [ 'OS in ["linux", "freebsd", "openbsd", "solaris"]', {
'sources!': [
'../src/utils/SkEGLContext_none.cpp',
],
@@ -124,18 +124,39 @@
'-lGLU',
],
},
- }],
- [ 'OS != "win"', {
+ },{ #else if 'OS not in ["linux", "freebsd", "openbsd", "solaris"]'
+ 'include_dirs!': [
+ '../include/utils/unix',
+ ],
'sources!': [
- '../src/utils/win/skia_win.cpp',
- '../src/utils/win/SkEGLContext_Win.cpp',
- '../src/utils/win/SkOSWindow_Win.cpp',
+ '../src/utils/unix/keysym2ucs.c',
+ '../src/utils/unix/SkEGLContext_Unix.cpp',
+ '../src/utils/unix/SkOSWindow_Unix.cpp',
],
}],
[ 'OS == "win"', {
'sources!': [
'../src/utils/SkEGLContext_none.cpp',
],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/utils/win',
+ ],
+ },
+ },{ #else if 'OS != "win"'
+ 'include_dirs!': [
+ '../include/utils/win',
+ ],
+ 'sources!': [
+ '../include/utils/win/SkAutoCoInitialize.h',
+ '../include/utils/win/SkIStream.h',
+ '../include/utils/win/SkTScopedComPtr.h',
+ '../src/utils/win/SkAutoCoInitialize.cpp',
+ '../src/utils/win/skia_win.cpp',
+ '../src/utils/win/SkEGLContext_Win.cpp',
+ '../src/utils/win/SkIStream.cpp',
+ '../src/utils/win/SkOSWindow_Win.cpp',
+ ],
}],
],
'direct_dependent_settings': {
diff --git a/include/utils/win/SkAutoCoInitialize.h b/include/utils/win/SkAutoCoInitialize.h
new file mode 100644
index 0000000..8819047
--- /dev/null
+++ b/include/utils/win/SkAutoCoInitialize.h
@@ -0,0 +1,37 @@
+/*
+ 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.
+ */
+
+#ifndef SkAutoCo_DEFINED
+#define SkAutoCo_DEFINED
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include "SkTemplates.h"
+
+/**
+ * An instance of this class initializes COM on creation
+ * and closes the COM library on destruction.
+ */
+class AutoCoInitialize : SkNoncopyable {
+private:
+ HRESULT fHR;
+public:
+ AutoCoInitialize();
+ ~AutoCoInitialize();
+ HRESULT getHR();
+};
+
+#endif
diff --git a/include/utils/win/SkIStream.h b/include/utils/win/SkIStream.h
new file mode 100644
index 0000000..bc8aff5
--- /dev/null
+++ b/include/utils/win/SkIStream.h
@@ -0,0 +1,135 @@
+/*
+ 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.
+ */
+
+#ifndef SkIStream_DEFINED
+#define SkIStream_DEFINED
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <ole2.h>
+
+class SkStream;
+class SkWStream;
+
+/**
+ * A bare IStream implementation which properly reference counts
+ * but returns E_NOTIMPL for all ISequentialStream and IStream methods.
+ */
+class SkBaseIStream : public IStream {
+private:
+ LONG _refcount;
+
+protected:
+ explicit SkBaseIStream();
+ virtual ~SkBaseIStream();
+
+public:
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid
+ , void ** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // ISequentialStream Interface
+public:
+ virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(void const* pv
+ , ULONG cb
+ , ULONG* pcbWritten);
+
+ // IStream Interface
+public:
+ virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER);
+
+ virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream*
+ , ULARGE_INTEGER
+ , ULARGE_INTEGER*
+ , ULARGE_INTEGER*);
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE Revert(void);
+
+ virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER
+ , ULARGE_INTEGER
+ , DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER
+ , ULARGE_INTEGER
+ , DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(IStream **);
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove
+ , DWORD dwOrigin
+ , ULARGE_INTEGER* lpNewFilePointer);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg
+ , DWORD grfStatFlag);
+};
+
+/**
+ * A minimal read-only IStream implementation which wraps an SkIStream.
+ */
+class SkIStream : public SkBaseIStream {
+private:
+ SkStream *fSkStream;
+ bool fUnrefOnRelease;
+
+ SkIStream(SkStream* stream, bool unrefOnRelease);
+ virtual ~SkIStream();
+
+public:
+ HRESULT static CreateFromSkStream(SkStream* stream
+ , bool unrefOnRelease
+ , IStream ** ppStream);
+
+ virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(void const* pv
+ , ULONG cb
+ , ULONG* pcbWritten);
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove
+ , DWORD dwOrigin
+ , ULARGE_INTEGER* lpNewFilePointer);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg
+ , DWORD grfStatFlag);
+};
+
+/**
+ * A minimal write-only IStream implementation which wraps an SkWIStream.
+ */
+class SkWIStream : public SkBaseIStream {
+private:
+ SkWStream *fSkWStream;
+
+ SkWIStream(SkWStream* stream);
+ virtual ~SkWIStream();
+
+public:
+ HRESULT static CreateFromSkWStream(SkWStream* stream, IStream ** ppStream);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(void const* pv
+ , ULONG cb
+ , ULONG* pcbWritten);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg
+ , DWORD grfStatFlag);
+};
+
+#endif
diff --git a/include/utils/win/SkTScopedComPtr.h b/include/utils/win/SkTScopedComPtr.h
new file mode 100644
index 0000000..202dc7e
--- /dev/null
+++ b/include/utils/win/SkTScopedComPtr.h
@@ -0,0 +1,47 @@
+/*
+ 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.
+ */
+
+#ifndef SkSkTScopedPtr_DEFINED
+#define SkSkTScopedPtr_DEFINED
+
+#include "SkTemplates.h"
+
+template<typename T>
+class SkTScopedComPtr : SkNoncopyable {
+private:
+ T *fPtr;
+
+public:
+ explicit SkTScopedComPtr(T *ptr = NULL) : fPtr(ptr) { }
+ ~SkTScopedComPtr() {
+ 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; }
+};
+
+#endif
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp
index b53db3b..c4f1748 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 @@
}
//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 @@
}
//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 @@
}
//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 @@
}
//Create a format converter.
- scoped_com_ptr<IWICFormatConverter> piFormatConverter;
+ SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
if (SUCCEEDED(hr)) {
hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
}
@@ -230,7 +119,7 @@
}
//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 @@
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 @@
);
}
- //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 @@
}
//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 @@
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 0000000..7249341
--- /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 0000000..29e1c87
--- /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;
+}