diff options
-rw-r--r-- | gyp/core.gypi | 1 | ||||
-rw-r--r-- | gyp/ports.gyp | 4 | ||||
-rw-r--r-- | include/core/SkOSFile.h | 16 | ||||
-rw-r--r-- | include/core/SkStream.h | 319 | ||||
-rw-r--r-- | src/core/SkData.cpp | 99 | ||||
-rw-r--r-- | src/core/SkFDStream.cpp | 104 | ||||
-rw-r--r-- | src/core/SkStream.cpp | 285 | ||||
-rw-r--r-- | src/ports/SkFontHost_fontconfig.cpp | 30 | ||||
-rw-r--r-- | src/ports/SkOSFile_none.cpp | 18 | ||||
-rw-r--r-- | src/ports/SkOSFile_posix.cpp | 63 | ||||
-rw-r--r-- | src/ports/SkOSFile_stdio.cpp | 79 | ||||
-rw-r--r-- | src/ports/SkOSFile_win.cpp | 99 | ||||
-rw-r--r-- | src/utils/win/SkDWriteFontFileStream.cpp | 135 | ||||
-rw-r--r-- | src/utils/win/SkDWriteFontFileStream.h | 11 | ||||
-rw-r--r-- | tests/StreamTest.cpp | 76 |
15 files changed, 640 insertions, 699 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi index d472c6d796..ab73ede52b 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -78,7 +78,6 @@ '<(skia_src_path)/core/SkEdge.h', '<(skia_src_path)/core/SkError.cpp', '<(skia_src_path)/core/SkErrorInternals.h', - '<(skia_src_path)/core/SkFDStream.cpp', '<(skia_src_path)/core/SkFP.h', '<(skia_src_path)/core/SkFilterProc.cpp', '<(skia_src_path)/core/SkFilterProc.h', diff --git a/gyp/ports.gyp b/gyp/ports.gyp index abbe16ba69..fc9bb9ba4c 100644 --- a/gyp/ports.gyp +++ b/gyp/ports.gyp @@ -31,7 +31,9 @@ '../src/ports/SkThread_win.cpp', '../src/ports/SkMemory_malloc.cpp', + '../src/ports/SkOSFile_posix.cpp', '../src/ports/SkOSFile_stdio.cpp', + '../src/ports/SkOSFile_win.cpp', '../src/ports/SkTime_Unix.cpp', '../src/ports/SkTime_win.cpp', '../src/ports/SkXMLParser_empty.cpp', @@ -140,12 +142,14 @@ 'sources!': [ # these are used everywhere but windows '../src/ports/SkDebug_stdio.cpp', '../src/ports/SkTime_Unix.cpp', + '../src/ports/SkOSFile_posix.cpp', ], }, { # else !win 'sources!': [ '../src/ports/SkDebug_win.cpp', '../src/ports/SkFontHost_win.cpp', '../src/ports/SkFontHost_win_dw.cpp', + '../src/ports/SkOSFile_win.cpp', '../src/ports/SkThread_win.cpp', '../src/ports/SkTime_win.cpp', ], diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h index 8564d43027..11330a03b1 100644 --- a/include/core/SkOSFile.h +++ b/include/core/SkOSFile.h @@ -48,9 +48,23 @@ char* sk_fgets(char* str, int size, SkFILE* f); void sk_fflush(SkFILE*); -int sk_fseek(SkFILE*, size_t, int); +bool sk_fseek(SkFILE*, size_t); +bool sk_fmove(SkFILE*, long); size_t sk_ftell(SkFILE*); +/** Maps a file into memory. Returns the address and length on success, NULL otherwise. + * The mapping is read only. + */ +void* sk_fmmap(SkFILE* f, size_t* length); + +/** Unmaps a file previously mapped by sk_fmmap. + * The length parameter must be the same as returned from sk_fmmap. + */ +void sk_fmunmap(const void* addr, size_t length); + +/** Returns true if the two point at the exact same filesystem object. */ +bool sk_fidentical(SkFILE* a, SkFILE* b); + // Returns true if something (file, directory, ???) exists at this path. bool sk_exists(const char *path); diff --git a/include/core/SkStream.h b/include/core/SkStream.h index 310f939439..31ed7bc6d4 100644 --- a/include/core/SkStream.h +++ b/include/core/SkStream.h @@ -13,6 +13,12 @@ class SkData; +class SkStream; +class SkStreamRewindable; +class SkStreamSeekable; +class SkStreamAsset; +class SkStreamMemory; + /** * SkStream -- abstraction for a source of bytes. Subclasses can be backed by * memory, or a file, or something else. @@ -30,50 +36,43 @@ class SkData; * no more data (at EOF or hit an error). The caller should *not* call again * in hopes of fulfilling more of the request. */ -class SK_API SkStream : public SkRefCnt { +class SK_API SkStream : public SkRefCnt { //TODO: remove SkRefCnt public: /** * Attempts to open the specified file, and return a stream to it (using * mmap if available). On success, the caller must call unref() on the * returned object. On failure, returns NULL. */ - static SkStream* NewFromFile(const char path[]); + static SkStreamAsset* NewFromFile(const char path[]); SK_DECLARE_INST_COUNT(SkStream) - /** Called to rewind to the beginning of the stream. If this cannot be - done, return false. - */ - virtual bool rewind() = 0; - /** If this stream represents a file, this method returns the file's name. - If it does not, it returns NULL (the default behavior). - */ - virtual const char* getFileName(); - /** Called to read or skip size number of bytes. - If buffer is NULL and size > 0, skip that many bytes, returning how many were skipped. - If buffer is NULL and size == 0, return the total length of the stream. - If buffer != NULL, copy the requested number of bytes into buffer, returning how many were copied. - @param buffer If buffer is NULL, ignore and just skip size bytes, otherwise copy size bytes into buffer - @param size The number of bytes to skip or copy - @return bytes read on success - */ + /** Reads or skips size number of bytes. + * If buffer == NULL, skip size bytes, return how many were skipped. + * If buffer != NULL, copy size bytes into buffer, return how many were copied. + * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer + * @param size the number of bytes to skip or copy + * @return bytes read on success + */ virtual size_t read(void* buffer, size_t size) = 0; - /** Return the total length of the stream. - */ - size_t getLength() { return this->read(NULL, 0); } - - /** Skip the specified number of bytes, returning the actual number - of bytes that could be skipped. - */ - size_t skip(size_t bytes); - - /** If the stream is backed by RAM, this method returns the starting - address for the data. If not (i.e. it is backed by a file or other - structure), this method returns NULL. - The default implementation returns NULL. - */ - virtual const void* getMemoryBase(); + /** Skip size number of bytes. + * @return the actual number bytes that could be skipped. + */ + size_t skip(size_t size) { + //return this->read(NULL, size); + //TODO: remove this old logic after updating existing implementations + return 0 == size ? 0 : this->read(NULL, size); + } + + /** Returns true if there are no more bytes to be read. + * In Progress: do not use until all implementations are updated. + * TODO: after this is implemented everywhere, make pure virtual. + */ + virtual bool isAtEnd() const { + SkASSERT(false); + return true; + } int8_t readS8(); int16_t readS16(); @@ -93,10 +92,100 @@ public: */ SkData* readData(); +//SkStreamRewindable + /** Rewinds to the beginning of the stream. If this cannot be done, return false. */ + virtual bool rewind() { return false; } + + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned at the beginning of its data. + */ + virtual SkStreamRewindable* duplicate() const { return NULL; } + +//SkStreamSeekable + /** Returns true if this stream can report it's current position. */ + virtual bool hasPosition() const { return false; } + /** Returns the current position in the stream. If this cannot be done, returns 0. */ + virtual size_t getPosition() const { return 0; } + + /** Seeks to an absolute position in the stream. If this cannot be done, returns false. + * If an attempt is made to seek past the end of the stream, the position will be set + * to the end of the stream. + */ + virtual bool seek(size_t position) { return false; } + + /** Seeks to an relative offset in the stream. If this cannot be done, returns false. + * If an attempt is made to move to a position outside the stream, the position will be set + * to the closest point within the stream (beginning or end). + */ + virtual bool move(long offset) { return false; } + + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned the same as this stream. + */ + virtual SkStreamSeekable* fork() const { return NULL; } + +//SkStreamAsset + /** Returns true if this stream can report it's total length. */ + virtual bool hasLength() const { return false; } + /** Returns the total length of the stream. If this cannot be done, returns 0. */ + virtual size_t getLength() const { + //return 0; + //TODO: remove the following after everyone is updated. + return ((SkStream*)this)->read(NULL, 0); + } + +//SkStreamMemory + /** Returns the starting address for the data. If this cannot be done, returns NULL. */ + //TODO: replace with virtual const SkData* getData() + virtual const void* getMemoryBase() { return NULL; } + private: typedef SkRefCnt INHERITED; }; +/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */ +class SK_API SkStreamRewindable : public SkStream { +public: + //TODO: remove the following after everyone is updated (ensures new behavior on new classes). + virtual bool isAtEnd() const SK_OVERRIDE = 0; + //TODO: remove the following after everyone is updated (ensures new behavior on new classes). + virtual size_t getLength() const SK_OVERRIDE { return 0; } + + virtual bool rewind() SK_OVERRIDE = 0; + virtual SkStreamRewindable* duplicate() const SK_OVERRIDE = 0; +}; + +/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */ +class SK_API SkStreamSeekable : public SkStreamRewindable { +public: + virtual SkStreamSeekable* duplicate() const SK_OVERRIDE = 0; + + virtual bool hasPosition() const SK_OVERRIDE { return true; } + virtual size_t getPosition() const SK_OVERRIDE = 0; + virtual bool seek(size_t position) SK_OVERRIDE = 0; + virtual bool move(long offset) SK_OVERRIDE = 0; + virtual SkStreamSeekable* fork() const SK_OVERRIDE = 0; +}; + +/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */ +class SK_API SkStreamAsset : public SkStreamSeekable { +public: + virtual SkStreamAsset* duplicate() const SK_OVERRIDE = 0; + virtual SkStreamAsset* fork() const SK_OVERRIDE = 0; + + virtual bool hasLength() const SK_OVERRIDE { return true; } + virtual size_t getLength() const SK_OVERRIDE = 0; +}; + +/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */ +class SK_API SkStreamMemory : public SkStreamAsset { +public: + virtual SkStreamMemory* duplicate() const SK_OVERRIDE = 0; + virtual SkStreamMemory* fork() const SK_OVERRIDE = 0; + + virtual const void* getMemoryBase() SK_OVERRIDE = 0; +}; + class SK_API SkWStream : SkNoncopyable { public: SK_DECLARE_INST_COUNT_ROOT(SkWStream) @@ -147,81 +236,76 @@ public: struct SkFILE; -/** A stream that reads from a FILE*, which is opened in the constructor and - closed in the destructor - */ -class SK_API SkFILEStream : public SkStream { +/** A stream that wraps a C FILE* file stream. */ +class SK_API SkFILEStream : public SkStreamAsset { public: SK_DECLARE_INST_COUNT(SkFILEStream) - /** Initialize the stream by calling fopen on the specified path. Will be - closed in the destructor. + /** Initialize the stream by calling sk_fopen on the specified path. + * This internal stream will be closed in the destructor. */ explicit SkFILEStream(const char path[] = NULL); + + enum Ownership { + kCallerPasses_Ownership, + kCallerRetains_Ownership + }; + /** Initialize the stream with an existing C file stream. + * While this stream exists, it assumes exclusive access to the C file stream. + * The C file stream will be closed in the destructor unless the caller specifies + * kCallerRetains_Ownership. + */ + explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership); + virtual ~SkFILEStream(); - /** Returns true if the current path could be opened. - */ + /** Returns true if the current path could be opened. */ bool isValid() const { return fFILE != NULL; } - /** Close the current file, and open a new file with the specified - path. If path is NULL, just close the current file. - */ + + /** Close the current file, and open a new file with the specified path. + * If path is NULL, just close the current file. + */ void setPath(const char path[]); - virtual bool rewind() SK_OVERRIDE; virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; - virtual const char* getFileName() SK_OVERRIDE; - -private: - SkFILE* fFILE; - SkString fName; - - typedef SkStream INHERITED; -}; + virtual bool isAtEnd() const SK_OVERRIDE; -/** A stream that reads from a file descriptor - */ -class SK_API SkFDStream : public SkStream { -public: - SK_DECLARE_INST_COUNT(SkFDStream) + virtual bool rewind() SK_OVERRIDE; + virtual SkStreamAsset* duplicate() const SK_OVERRIDE; - /** Initialize the stream with a dup() of the specified file descriptor. - If closeWhenDone is true, then the descriptor will be closed in the - destructor. - */ - SkFDStream(int fileDesc, bool closeWhenDone); - virtual ~SkFDStream(); + virtual size_t getPosition() const SK_OVERRIDE; + virtual bool seek(size_t position) SK_OVERRIDE; + virtual bool move(long offset) SK_OVERRIDE; + virtual SkStreamAsset* fork() const SK_OVERRIDE; - /** Returns true if the current path could be opened. - */ - bool isValid() const { return fFD >= 0; } + virtual size_t getLength() const SK_OVERRIDE; - virtual bool rewind() SK_OVERRIDE; - virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; - virtual const char* getFileName() SK_OVERRIDE { return NULL; } + const void* getMemoryBase() SK_OVERRIDE; private: - int fFD; - bool fCloseWhenDone; + SkFILE* fFILE; + SkString fName; + Ownership fOwnership; + // fData is lazilly initialized when needed. + mutable SkAutoTUnref<SkData> fData; - typedef SkStream INHERITED; + typedef SkStreamAsset INHERITED; }; -class SK_API SkMemoryStream : public SkStream { +class SK_API SkMemoryStream : public SkStreamMemory { public: SK_DECLARE_INST_COUNT(SkMemoryStream) SkMemoryStream(); - /** We allocate (and free) the memory. Write to it via getMemoryBase() - */ + + /** We allocate (and free) the memory. Write to it via getMemoryBase() */ SkMemoryStream(size_t length); - /** if copyData is true, the stream makes a private copy of the data - */ + + /** If copyData is true, the stream makes a private copy of the data. */ SkMemoryStream(const void* data, size_t length, bool copyData = false); - /** - * Use the specified data as the memory for this stream. The stream will - * call ref() on the data (assuming it is not null). + /** Use the specified data as the memory for this stream. + * The stream will call ref() on the data (assuming it is not NULL). */ SkMemoryStream(SkData*); @@ -239,81 +323,42 @@ public: */ void setMemoryOwned(const void* data, size_t length); - /** - * Return the stream's data in a SkData. The caller must call unref() when - * it is finished using the data. + /** Return the stream's data in a SkData. + * The caller must call unref() when it is finished using the data. */ SkData* copyToData() const; /** - * Use the specified data as the memory for this stream. The stream will - * call ref() on the data (assuming it is not null). The function returns - * the data parameter as a convenience. + * Use the specified data as the memory for this stream. + * The stream will call ref() on the data (assuming it is not NULL). + * The function returns the data parameter as a convenience. */ SkData* setData(SkData*); void skipToAlign4(); - virtual bool rewind() SK_OVERRIDE; - virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; - virtual const void* getMemoryBase() SK_OVERRIDE; const void* getAtPos(); - size_t seek(size_t offset); size_t peek() const { return fOffset; } -private: - SkData* fData; - size_t fOffset; + virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; + virtual bool isAtEnd() const SK_OVERRIDE; - typedef SkStream INHERITED; -}; + virtual bool rewind() SK_OVERRIDE; + virtual SkMemoryStream* duplicate() const SK_OVERRIDE; -/** \class SkBufferStream - This is a wrapper class that adds buffering to another stream. - The caller can provide the buffer, or ask SkBufferStream to allocated/free - it automatically. -*/ -class SK_API SkBufferStream : public SkStream { -public: - SK_DECLARE_INST_COUNT(SkBufferStream) + virtual size_t getPosition() const SK_OVERRIDE; + virtual bool seek(size_t position) SK_OVERRIDE; + virtual bool move(long offset) SK_OVERRIDE; + virtual SkMemoryStream* fork() const SK_OVERRIDE; - /** Provide the stream to be buffered (proxy), and the size of the buffer that - should be used. This will be allocated and freed automatically. If bufferSize is 0, - a default buffer size will be used. - The proxy stream is referenced, and will be unreferenced in when the - bufferstream is destroyed. - */ - SkBufferStream(SkStream* proxy, size_t bufferSize = 0); - /** Provide the stream to be buffered (proxy), and a buffer and size to be used. - This buffer is owned by the caller, and must be at least bufferSize bytes big. - Passing NULL for buffer will cause the buffer to be allocated/freed automatically. - If buffer is not NULL, it is an error for bufferSize to be 0. - The proxy stream is referenced, and will be unreferenced in when the - bufferstream is destroyed. - */ - SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize); - virtual ~SkBufferStream(); + virtual size_t getLength() const SK_OVERRIDE; - virtual bool rewind() SK_OVERRIDE; - virtual const char* getFileName() SK_OVERRIDE; - virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; virtual const void* getMemoryBase() SK_OVERRIDE; private: - enum { - kDefaultBufferSize = 128 - }; - // illegal - SkBufferStream(const SkBufferStream&); - SkBufferStream& operator=(const SkBufferStream&); - - SkStream* fProxy; - char* fBuffer; - size_t fOrigBufferSize, fBufferSize, fBufferOffset; - bool fWeOwnTheBuffer; - - void init(void*, size_t); + SkData* fData; + size_t fOffset; - typedef SkStream INHERITED; + typedef SkStreamMemory INHERITED; }; ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkData.cpp b/src/core/SkData.cpp index e47bbce28e..32e029740a 100644 --- a/src/core/SkData.cpp +++ b/src/core/SkData.cpp @@ -9,16 +9,6 @@ #include "SkFlattenableBuffers.h" #include "SkOSFile.h" -#if SK_MMAP_SUPPORT - #include <unistd.h> - #include <sys/mman.h> - #include <fcntl.h> - #include <errno.h> - #include <unistd.h> -#else - #include <io.h> -#endif - SK_DEFINE_INST_COUNT(SkData) SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) { @@ -92,96 +82,27 @@ SkData* SkData::NewWithProc(const void* data, size_t length, return new SkData(data, length, proc, context); } -// assumes context is a SkData -static void sk_dataref_releaseproc(const void*, size_t, void* context) { - SkData* src = reinterpret_cast<SkData*>(context); - src->unref(); -} - -#if SK_MMAP_SUPPORT - -static void sk_munmap_releaseproc(const void* addr, size_t length, void*) { - munmap(const_cast<void*>(addr), length); -} - -SkData* SkData::NewFromFILE(SkFILE* f) { - size_t size = sk_fgetsize(f); - if (0 == size) { - return NULL; - } - - int fd = fileno((FILE*)f); - if (fd < 0) { - return NULL; - } - - void* addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (MAP_FAILED == addr) { - return NULL; - } - - return SkData::NewWithProc(addr, size, sk_munmap_releaseproc, NULL); -} - -#elif defined(SK_BUILD_FOR_WIN32) - -template <typename HandleType, HandleType InvalidValue, BOOL (WINAPI * Close)(HandleType)> -class SkAutoTHandle : SkNoncopyable { -public: - SkAutoTHandle(HandleType handle) : fHandle(handle) { } - ~SkAutoTHandle() { Close(fHandle); } - operator HandleType() { return fHandle; } - bool isValid() { return InvalidValue != fHandle; } -private: - HandleType fHandle; -}; -typedef SkAutoTHandle<HANDLE, INVALID_HANDLE_VALUE, CloseHandle> SkAutoWinFile; -typedef SkAutoTHandle<HANDLE, NULL, CloseHandle> SkAutoWinMMap; - -static void sk_munmap_releaseproc(const void* addr, size_t, void*) { - UnmapViewOfFile(addr); +// assumes fPtr was allocated with sk_fmmap +static void sk_mmap_releaseproc(const void* addr, size_t length, void*) { + sk_fmunmap(addr, length); } SkData* SkData::NewFromFILE(SkFILE* f) { - size_t size = sk_fgetsize(f); - if (0 == size) { - return NULL; - } - - int fileno = _fileno((FILE*)f); - if (fileno < 0) { - return NULL; - } - - HANDLE file = (HANDLE)_get_osfhandle(fileno); - if (INVALID_HANDLE_VALUE == file) { - return NULL; - } - - SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL)); - if (!mmap.isValid()) { - //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report. - return NULL; - } - - // Eventually call UnmapViewOfFile - void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0); + size_t size; + void* addr = sk_fmmap(f, &size); if (NULL == addr) { - //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report. return NULL; } - return SkData::NewWithProc(addr, size, sk_munmap_releaseproc, NULL); + return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); } -#else - -SkData* SkData::NewFromFILE(SkFILE* f) { - return NULL; +// assumes context is a SkData +static void sk_dataref_releaseproc(const void*, size_t, void* context) { + SkData* src = reinterpret_cast<SkData*>(context); + src->unref(); } -#endif - SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) { /* We could, if we wanted/need to, just make a deep copy of src's data, diff --git a/src/core/SkFDStream.cpp b/src/core/SkFDStream.cpp deleted file mode 100644 index ed94229ed1..0000000000 --- a/src/core/SkFDStream.cpp +++ /dev/null @@ -1,104 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkStream.h" - -#ifdef SK_BUILD_FOR_WIN - -// -1 means isValid() will return false -SkFDStream::SkFDStream(int, bool) : fFD(-1), fCloseWhenDone(false) {} -SkFDStream::~SkFDStream() {} -bool SkFDStream::rewind() { return false; } -size_t SkFDStream::read(void*, size_t) { return 0; } - -#else - -#include <unistd.h> - -//#define TRACE_FDSTREAM - -SkFDStream::SkFDStream(int fileDesc, bool closeWhenDone) - : fFD(fileDesc), fCloseWhenDone(closeWhenDone) { -} - -SkFDStream::~SkFDStream() { - if (fFD >= 0 && fCloseWhenDone) { - ::close(fFD); - } -} - -bool SkFDStream::rewind() { - if (fFD >= 0) { - off_t value = ::lseek(fFD, 0, SEEK_SET); -#ifdef TRACE_FDSTREAM - if (value) { - SkDebugf("xxxxxxxxxxxxxx rewind failed %d\n", value); - } -#endif - return value == 0; - } - return false; -} - -size_t SkFDStream::read(void* buffer, size_t size) { - if (fFD >= 0) { - if (buffer == NULL && size == 0) { // request total size - off_t curr = ::lseek(fFD, 0, SEEK_CUR); - if (curr < 0) { -#ifdef TRACE_FDSTREAM - SkDebugf("xxxxxxxxxxxxx lseek failed 0 CURR\n"); -#endif - return 0; // error - } - off_t size = ::lseek(fFD, 0, SEEK_END); - if (size < 0) { -#ifdef TRACE_FDSTREAM - SkDebugf("xxxxxxxxxxxxx lseek failed 0 END\n"); -#endif - size = 0; // error - } - if (::lseek(fFD, curr, SEEK_SET) != curr) { - // can't restore, error -#ifdef TRACE_FDSTREAM - SkDebugf("xxxxxxxxxxxxx lseek failed %d SET\n", curr); -#endif - return 0; - } - return (size_t) size; - } else if (NULL == buffer) { // skip - off_t oldCurr = ::lseek(fFD, 0, SEEK_CUR); - if (oldCurr < 0) { -#ifdef TRACE_FDSTREAM - SkDebugf("xxxxxxxxxxxxx lseek1 failed %d CUR\n", oldCurr); -#endif - return 0; // error; - } - off_t newCurr = ::lseek(fFD, size, SEEK_CUR); - if (newCurr < 0) { -#ifdef TRACE_FDSTREAM - SkDebugf("xxxxxxxxxxxxx lseek2 failed %d CUR\n", newCurr); -#endif - return 0; // error; - } - // return the actual amount we skipped - return (size_t) (newCurr - oldCurr); - } else { // read - ssize_t actual = ::read(fFD, buffer, size); - // our API can't return an error, so we return 0 - if (actual < 0) { -#ifdef TRACE_FDSTREAM - SkDebugf("xxxxxxxxxxxxx read failed %d actual %d\n", size, actual); -#endif - actual = 0; - } - return actual; - } - } - return 0; -} - -#endif diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp index 74734e6d98..91de88adac 100644 --- a/src/core/SkStream.cpp +++ b/src/core/SkStream.cpp @@ -16,9 +16,7 @@ SK_DEFINE_INST_COUNT(SkStream) SK_DEFINE_INST_COUNT(SkWStream) SK_DEFINE_INST_COUNT(SkFILEStream) -SK_DEFINE_INST_COUNT(SkFDStream) SK_DEFINE_INST_COUNT(SkMemoryStream) -SK_DEFINE_INST_COUNT(SkBufferStream) SK_DEFINE_INST_COUNT(SkFILEWStream) SK_DEFINE_INST_COUNT(SkMemoryWStream) SK_DEFINE_INST_COUNT(SkDynamicMemoryWStream) @@ -26,26 +24,6 @@ SK_DEFINE_INST_COUNT(SkDebugWStream) /////////////////////////////////////////////////////////////////////////////// -const char* SkStream::getFileName() -{ - // override in subclass if you represent a file - return NULL; -} - -const void* SkStream::getMemoryBase() -{ - // override in subclass if you represent a memory block - return NULL; -} - -size_t SkStream::skip(size_t size) -{ - /* Check for size == 0, and just return 0. If we passed that - to read(), it would interpret it as a request for the entire - size of the stream. - */ - return size ? this->read(NULL, size) : 0; -} int8_t SkStream::readS8() { int8_t value; @@ -221,12 +199,17 @@ bool SkWStream::writeData(const SkData* data) { /////////////////////////////////////////////////////////////////////////////// -SkFILEStream::SkFILEStream(const char file[]) : fName(file) { +SkFILEStream::SkFILEStream(const char file[]) : fName(file), fOwnership(kCallerPasses_Ownership) { fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL; } +SkFILEStream::SkFILEStream(FILE* file, Ownership ownership) + : fFILE((SkFILE*)file) + , fOwnership(ownership) { +} + SkFILEStream::~SkFILEStream() { - if (fFILE) { + if (fFILE && fOwnership != kCallerRetains_Ownership) { sk_fclose(fFILE); } } @@ -242,8 +225,15 @@ void SkFILEStream::setPath(const char path[]) { } } -const char* SkFILEStream::getFileName() { - return fName.c_str(); +size_t SkFILEStream::read(void* buffer, size_t size) { + if (fFILE) { + return sk_fread(buffer, size, fFILE); + } + return 0; +} + +bool SkFILEStream::isAtEnd() const { + return sk_feof(fFILE); } bool SkFILEStream::rewind() { @@ -258,15 +248,56 @@ bool SkFILEStream::rewind() { return false; } -size_t SkFILEStream::read(void* buffer, size_t size) { - if (fFILE) { - if (buffer == NULL && size == 0) { // special signature, they want the total size - return sk_fgetsize(fFILE); - } else { - return sk_fread(buffer, size, fFILE); +SkStreamAsset* SkFILEStream::duplicate() const { + if (NULL == fFILE) { + return new SkMemoryStream(); + } + + if (NULL != fData.get()) { + return new SkMemoryStream(fData); + } + + if (!fName.isEmpty()) { + SkAutoTUnref<SkFILEStream> that(new SkFILEStream(fName.c_str())); + if (sk_fidentical(that->fFILE, this->fFILE)) { + return that.detach(); } } - return 0; + + fData.reset(SkData::NewFromFILE(fFILE)); + if (NULL == fData.get()) { + return NULL; + } + return new SkMemoryStream(fData); +} + +size_t SkFILEStream::getPosition() const { + return sk_ftell(fFILE); +} + +bool SkFILEStream::seek(size_t position) { + return sk_fseek(fFILE, position); +} + +bool SkFILEStream::move(long offset) { + return sk_fmove(fFILE, offset); +} + +SkStreamAsset* SkFILEStream::fork() const { + SkAutoTUnref<SkStreamAsset> that(this->duplicate()); + that->seek(this->getPosition()); + return that.detach(); +} + +size_t SkFILEStream::getLength() const { + return sk_fgetsize(fFILE); +} + +const void* SkFILEStream::getMemoryBase() { + if (NULL == fData.get()) { + return NULL; + } + return fData->data(); } /////////////////////////////////////////////////////////////////////////////// @@ -341,22 +372,9 @@ void SkMemoryStream::skipToAlign4() { fOffset += -(int)fOffset & 0x03; } -bool SkMemoryStream::rewind() { - fOffset = 0; - return true; -} - size_t SkMemoryStream::read(void* buffer, size_t size) { size_t dataSize = fData->size(); - if (buffer == NULL && size == 0) // special signature, they want the total size - return dataSize; - - // if buffer is NULL, seek ahead by size - - if (size == 0) { - return 0; - } if (size > dataSize - fOffset) { size = dataSize - fOffset; } @@ -367,171 +385,50 @@ size_t SkMemoryStream::read(void* buffer, size_t size) { return size; } -const void* SkMemoryStream::getMemoryBase() { - return fData->data(); -} - -const void* SkMemoryStream::getAtPos() { - return fData->bytes() + fOffset; +bool SkMemoryStream::isAtEnd() const { + return fOffset == fData->size(); } -size_t SkMemoryStream::seek(size_t offset) { - if (offset > fData->size()) { - offset = fData->size(); - } - fOffset = offset; - return offset; +bool SkMemoryStream::rewind() { + fOffset = 0; + return true; } -/////////////////////////////////////////////////////////////////////////////// - -SkBufferStream::SkBufferStream(SkStream* proxy, size_t bufferSize) - : fProxy(proxy) -{ - SkASSERT(proxy != NULL); - proxy->ref(); - this->init(NULL, bufferSize); +SkMemoryStream* SkMemoryStream::duplicate() const { + return SkNEW_ARGS(SkMemoryStream, (fData)); } -SkBufferStream::SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize) - : fProxy(proxy) -{ - SkASSERT(proxy != NULL); - SkASSERT(buffer == NULL || bufferSize != 0); // init(addr, 0) makes no sense, we must know how big their buffer is - proxy->ref(); - this->init(buffer, bufferSize); +size_t SkMemoryStream::getPosition() const { + return fOffset; } -void SkBufferStream::init(void* buffer, size_t bufferSize) -{ - if (bufferSize == 0) - bufferSize = kDefaultBufferSize; - - fOrigBufferSize = bufferSize; - fBufferSize = bufferSize; - fBufferOffset = bufferSize; // to trigger a reload on the first read() - - if (buffer == NULL) - { - fBuffer = (char*)sk_malloc_throw(fBufferSize); - fWeOwnTheBuffer = true; - } - else - { - fBuffer = (char*)buffer; - fWeOwnTheBuffer = false; - } +bool SkMemoryStream::seek(size_t position) { + fOffset = position > fData->size() + ? fData->size() + : position; + return true; } -SkBufferStream::~SkBufferStream() -{ - fProxy->unref(); - if (fWeOwnTheBuffer) - sk_free(fBuffer); +bool SkMemoryStream::move(long offset) { + return this->seek(fOffset + offset); } -bool SkBufferStream::rewind() -{ - fBufferOffset = fBufferSize = fOrigBufferSize; - return fProxy->rewind(); +SkMemoryStream* SkMemoryStream::fork() const { + SkAutoTUnref<SkMemoryStream> that(this->duplicate()); + that->seek(fOffset); + return that.detach(); } -const char* SkBufferStream::getFileName() -{ - return fProxy->getFileName(); +size_t SkMemoryStream::getLength() const { + return fData->size(); } -#ifdef SK_DEBUG -// #define SK_TRACE_BUFFERSTREAM -#endif - -size_t SkBufferStream::read(void* buffer, size_t size) { -#ifdef SK_TRACE_BUFFERSTREAM - SkDebugf("Request %d", size); -#endif - - if (buffer == NULL && size == 0) { - return fProxy->read(buffer, size); // requesting total size - } - - if (0 == size) { - return 0; - } - - // skip size bytes - if (NULL == buffer) { - size_t remaining = fBufferSize - fBufferOffset; - if (remaining >= size) { - fBufferOffset += size; - return size; - } - // if we get here, we are being asked to skip beyond our current buffer - // so reset our offset to force a read next time, and skip the diff - // in our proxy - fBufferOffset = fOrigBufferSize; - return remaining + fProxy->read(NULL, size - remaining); - } - - size_t s = size; - size_t actuallyRead = 0; - - // flush what we can from our fBuffer - if (fBufferOffset < fBufferSize) - { - if (s > fBufferSize - fBufferOffset) - s = fBufferSize - fBufferOffset; - memcpy(buffer, fBuffer + fBufferOffset, s); -#ifdef SK_TRACE_BUFFERSTREAM - SkDebugf(" flush %d", s); -#endif - size -= s; - fBufferOffset += s; - buffer = (char*)buffer + s; - actuallyRead = s; - } - - // check if there is more to read - if (size) - { - SkASSERT(fBufferOffset >= fBufferSize); // need to refill our fBuffer - - if (size < fBufferSize) // lets try to read more than the request - { - s = fProxy->read(fBuffer, fBufferSize); -#ifdef SK_TRACE_BUFFERSTREAM - SkDebugf(" read %d into fBuffer", s); -#endif - if (size > s) // they asked for too much - size = s; - if (size) - { - memcpy(buffer, fBuffer, size); - actuallyRead += size; -#ifdef SK_TRACE_BUFFERSTREAM - SkDebugf(" memcpy %d into dst", size); -#endif - } - - fBufferOffset = size; - fBufferSize = s; // record the (possibly smaller) size for the buffer - } - else // just do a direct read - { - actuallyRead += fProxy->read(buffer, size); -#ifdef SK_TRACE_BUFFERSTREAM - SkDebugf(" direct read %d", size); -#endif - } - } -#ifdef SK_TRACE_BUFFERSTREAM - SkDebugf("\n"); -#endif - return actuallyRead; +const void* SkMemoryStream::getMemoryBase() { + return fData->data(); } -const void* SkBufferStream::getMemoryBase() -{ - return fProxy->getMemoryBase(); +const void* SkMemoryStream::getAtPos() { + return fData->bytes() + fOffset; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -800,7 +697,7 @@ static SkData* mmap_filename(const char path[]) { return data; } -SkStream* SkStream::NewFromFile(const char path[]) { +SkStreamAsset* SkStream::NewFromFile(const char path[]) { SkAutoTUnref<SkData> data(mmap_filename(path)); if (data.get()) { return SkNEW_ARGS(SkMemoryStream, (data.get())); diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp index f42ab3fc99..a5aef56f1c 100644 --- a/src/ports/SkFontHost_fontconfig.cpp +++ b/src/ports/SkFontHost_fontconfig.cpp @@ -136,16 +136,30 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const { SkStream* stream = this->getLocalStream(); if (stream) { - // TODO: fix issue 1176. - // As of now open_stream will return a stream and unwind it, but the - // SkStream is not thread safe, and if two threads use the stream they - // may collide and print preview for example could still fail, - // or there could be some failures in rendering if this stream is used - // there. - stream->rewind(); - stream->ref(); // should have been provided by CreateFromStream() *ttcIndex = 0; + + SkAutoTUnref<SkStream> dupStream(stream->duplicate()); + if (dupStream) { + return dupStream.detach(); + } + + // TODO: update interface use, remove the following code in this block. + size_t length = stream->getLength(); + + const void* memory = stream->getMemoryBase(); + if (NULL != memory) { + return new SkMemoryStream(memory, length, true); + } + + SkAutoTMalloc<uint8_t> allocMemory(length); + stream->rewind(); + if (length == stream->read(allocMemory.get(), length)) { + return new SkMemoryStream(allocMemory.detach(), length); + } + + stream->rewind(); + stream->ref(); } else { SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); if (NULL == fci.get()) { diff --git a/src/ports/SkOSFile_none.cpp b/src/ports/SkOSFile_none.cpp new file mode 100644 index 0000000000..e22d22ed4d --- /dev/null +++ b/src/ports/SkOSFile_none.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkOSFile.h" + +bool sk_fidentical(SkFILE* a, SkFILE* b) { + return false; +} + +void sk_fmunmap(const void* addr, size_t length) { } + +void* sk_fmmap(SkFILE* f, size_t* size) { + return NULL; +} diff --git a/src/ports/SkOSFile_posix.cpp b/src/ports/SkOSFile_posix.cpp new file mode 100644 index 0000000000..c9da4db6b8 --- /dev/null +++ b/src/ports/SkOSFile_posix.cpp @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkOSFile.h" + +#include <stdio.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +typedef struct { + dev_t dev; + ino_t ino; +} SkFILEID; + +static bool sk_ino(SkFILE* a, SkFILEID* id) { + int fd = fileno((FILE*)a); + if (fd < 0) { + return 0; + } + struct stat status; + if (0 != fstat(fd, &status)) { + return 0; + } + id->dev = status.st_dev; + id->ino = status.st_ino; + return true; +} + +bool sk_fidentical(SkFILE* a, SkFILE* b) { + SkFILEID aID, bID; + return sk_ino(a, &aID) && sk_ino(b, &bID) + && aID.ino == bID.ino + && aID.dev == bID.dev; +} + +void sk_fmunmap(const void* addr, size_t length) { + munmap(const_cast<void*>(addr), length); +} + +void* sk_fmmap(SkFILE* f, size_t* size) { + size_t fileSize = sk_fgetsize(f); + if (0 == fileSize) { + return NULL; + } + + int fd = fileno((FILE*)f); + if (fd < 0) { + return NULL; + } + + void* addr = mmap(NULL, fileSize, PROT_READ, MAP_PRIVATE, fd, 0); + if (MAP_FAILED == addr) { + return NULL; + } + + *size = fileSize; + return addr; +} diff --git a/src/ports/SkOSFile_stdio.cpp b/src/ports/SkOSFile_stdio.cpp index 40c8745552..ad26c807c7 100644 --- a/src/ports/SkOSFile_stdio.cpp +++ b/src/ports/SkOSFile_stdio.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #include "SkOSFile.h" #include <errno.h> @@ -21,74 +19,65 @@ #include <unistd.h> #endif -SkFILE* sk_fopen(const char path[], SkFILE_Flags flags) -{ +SkFILE* sk_fopen(const char path[], SkFILE_Flags flags) { char perm[4]; char* p = perm; - if (flags & kRead_SkFILE_Flag) + if (flags & kRead_SkFILE_Flag) { *p++ = 'r'; - if (flags & kWrite_SkFILE_Flag) + } + if (flags & kWrite_SkFILE_Flag) { *p++ = 'w'; + } *p++ = 'b'; *p = 0; //TODO: on Windows fopen is just ASCII or the current code page, //convert to utf16 and use _wfopen - SkFILE* f = (SkFILE*)::fopen(path, perm); -#if 0 - if (NULL == f) - SkDebugf("sk_fopen failed for %s (%s), errno=%s\n", path, perm, strerror(errno)); -#endif - return f; + return (SkFILE*)::fopen(path, perm); } char* sk_fgets(char* str, int size, SkFILE* f) { return ::fgets(str, size, (FILE *)f); } - int sk_feof(SkFILE *f) { // no :: namespace qualifier because it breaks android return feof((FILE *)f); } -size_t sk_fgetsize(SkFILE* f) -{ +size_t sk_fgetsize(SkFILE* f) { SkASSERT(f); - long curr = ::ftell((FILE*)f); // remember where we are + long curr = ::ftell((FILE*)f); // remember where we are if (curr < 0) { return 0; } - ::fseek((FILE*)f, 0, SEEK_END); // go to the end - long size = ::ftell((FILE*)f); // record the size + + ::fseek((FILE*)f, 0, SEEK_END); // go to the end + long size = ::ftell((FILE*)f); // record the size if (size < 0) { size = 0; } - ::fseek((FILE*)f, curr, SEEK_SET); // go back to our prev loc + + ::fseek((FILE*)f, curr, SEEK_SET); // go back to our prev location return size; } -bool sk_frewind(SkFILE* f) -{ +bool sk_frewind(SkFILE* f) { SkASSERT(f); ::rewind((FILE*)f); -// ::fseek((FILE*)f, 0, SEEK_SET); return true; } -size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f) -{ +size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f) { SkASSERT(f); - if (buffer == NULL) - { + if (buffer == NULL) { size_t curr = ::ftell((FILE*)f); if ((long)curr == -1) { SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof((FILE*)f), ferror((FILE*)f))); return 0; } - // ::fseek((FILE*)f, (long)(curr + byteCount), SEEK_SET); int err = ::fseek((FILE*)f, (long)byteCount, SEEK_CUR); if (err != 0) { SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n", @@ -101,26 +90,40 @@ size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f) return ::fread(buffer, 1, byteCount, (FILE*)f); } -size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f) -{ +size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f) { SkASSERT(f); return ::fwrite(buffer, 1, byteCount, (FILE*)f); } -void sk_fflush(SkFILE* f) -{ +void sk_fflush(SkFILE* f) { SkASSERT(f); ::fflush((FILE*)f); } -void sk_fclose(SkFILE* f) -{ +bool sk_fseek(SkFILE* f, size_t byteCount) { + int err = ::fseek((FILE*)f, (long)byteCount, SEEK_SET); + return err == 0; +} + +bool sk_fmove(SkFILE* f, long byteCount) { + int err = ::fseek((FILE*)f, byteCount, SEEK_CUR); + return err == 0; +} + +size_t sk_ftell(SkFILE* f) { + long curr = ::ftell((FILE*)f); + if (curr < 0) { + return 0; + } + return curr; +} + +void sk_fclose(SkFILE* f) { SkASSERT(f); ::fclose((FILE*)f); } -bool sk_exists(const char *path) -{ +bool sk_exists(const char *path) { #ifdef _WIN32 return (0 == _access(path, 0)); #else @@ -128,8 +131,7 @@ bool sk_exists(const char *path) #endif } -bool sk_isdir(const char *path) -{ +bool sk_isdir(const char *path) { struct stat status; if (0 != stat(path, &status)) { return false; @@ -137,8 +139,7 @@ bool sk_isdir(const char *path) return SkToBool(status.st_mode & S_IFDIR); } -bool sk_mkdir(const char* path) -{ +bool sk_mkdir(const char* path) { if (sk_isdir(path)) { return true; } diff --git a/src/ports/SkOSFile_win.cpp b/src/ports/SkOSFile_win.cpp new file mode 100644 index 0000000000..fdf9ca5013 --- /dev/null +++ b/src/ports/SkOSFile_win.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkOSFile.h" + +#include <io.h> +#include <stdio.h> +#include <sys/stat.h> + +typedef struct { + ULONGLONG fVolume; + ULONGLONG fLsbSize; + ULONGLONG fMsbSize; +} SkFILEID; + +static bool sk_ino(SkFILE* f, SkFILEID* id) { + int fileno = _fileno((FILE*)f); + if (fileno < 0) { + return false; + } + + HANDLE file = (HANDLE)_get_osfhandle(fileno); + if (INVALID_HANDLE_VALUE == file) { + return false; + } + + //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo. + BY_HANDLE_FILE_INFORMATION info; + if (0 == GetFileInformationByHandle(file, &info)) { + return false; + } + id->fVolume = info.dwVolumeSerialNumber; + id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32); + id->fMsbSize = 0; + + return true; +} + +bool sk_fidentical(SkFILE* a, SkFILE* b) { + SkFILEID aID, bID; + return sk_ino(a, &aID) && sk_ino(b, &bID) + && aID.fLsbSize == bID.fLsbSize + && aID.fMsbSize == bID.fMsbSize + && aID.fVolume == bID.fVolume; +} + +template <typename HandleType, HandleType InvalidValue, BOOL (WINAPI * Close)(HandleType)> +class SkAutoTHandle : SkNoncopyable { +public: + SkAutoTHandle(HandleType handle) : fHandle(handle) { } + ~SkAutoTHandle() { Close(fHandle); } + operator HandleType() { return fHandle; } + bool isValid() { return InvalidValue != fHandle; } +private: + HandleType fHandle; +}; +typedef SkAutoTHandle<HANDLE, INVALID_HANDLE_VALUE, CloseHandle> SkAutoWinFile; +typedef SkAutoTHandle<HANDLE, NULL, CloseHandle> SkAutoWinMMap; + +void sk_fmunmap(const void* addr, size_t) { + UnmapViewOfFile(addr); +} + +void* sk_fmmap(SkFILE* f, size_t* length) { + size_t fileSize = sk_fgetsize(f); + if (0 == fileSize) { + return NULL; + } + + int fileno = _fileno((FILE*)f); + if (fileno < 0) { + return NULL; + } + + HANDLE file = (HANDLE)_get_osfhandle(fileno); + if (INVALID_HANDLE_VALUE == file) { + return NULL; + } + + SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL)); + if (!mmap.isValid()) { + //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report. + return NULL; + } + + // Eventually call UnmapViewOfFile + void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0); + if (NULL == addr) { + //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report. + return NULL; + } + + *length = fileSize; + return addr; +} diff --git a/src/utils/win/SkDWriteFontFileStream.cpp b/src/utils/win/SkDWriteFontFileStream.cpp index 1569158ee2..971fdb98b4 100644 --- a/src/utils/win/SkDWriteFontFileStream.cpp +++ b/src/utils/win/SkDWriteFontFileStream.cpp @@ -8,6 +8,7 @@ #include "SkTypes.h" #include "SkDWriteFontFileStream.h" #include "SkHRESULT.h" +#include "SkTScopedComPtr.h" #include <dwrite.h> #include <limits> @@ -16,11 +17,10 @@ // SkIDWriteFontFileStream SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) - : fFontFileStream(fontFileStream) + : fFontFileStream(SkRefComPtr(fontFileStream)) , fPos(0) , fLockedMemory(NULL) , fFragmentLock(NULL) { - fontFileStream->AddRef(); } SkDWriteFontFileStream::~SkDWriteFontFileStream() { @@ -29,44 +29,19 @@ SkDWriteFontFileStream::~SkDWriteFontFileStream() { } } -const void* SkDWriteFontFileStream::getMemoryBase() { - if (fLockedMemory) { - return fLockedMemory; - } - - UINT64 fileSize; - HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size"); - HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock), - "Could not lock file fragment."); - return fLockedMemory; -} - -bool SkDWriteFontFileStream::rewind() { - fPos = 0; - return true; -} - size_t SkDWriteFontFileStream::read(void* buffer, size_t size) { HRESULT hr = S_OK; if (NULL == buffer) { - UINT64 realFileSize = 0; - hr = fFontFileStream->GetFileSize(&realFileSize); - if (realFileSize > (std::numeric_limits<size_t>::max)()) { - return 0; - } - size_t fileSize = static_cast<size_t>(realFileSize); - if (size == 0) { - return fileSize; + size_t fileSize = this->getLength(); + + if (fPos + size > fileSize) { + size_t skipped = fileSize - fPos; + fPos = fileSize; + return skipped; } else { - if (fPos + size > fileSize) { - size_t skipped = fileSize - fPos; - fPos = fileSize; - return skipped; - } else { - fPos += size; - return size; - } + fPos += size; + return size; } } @@ -81,28 +56,78 @@ size_t SkDWriteFontFileStream::read(void* buffer, size_t size) { } //The read may have failed because we asked for too much data. + size_t fileSize = this->getLength(); + if (fPos + size <= fileSize) { + //This means we were within bounds, but failed for some other reason. + return 0; + } + + size_t read = fileSize - fPos; + hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock); + if (SUCCEEDED(hr)) { + memcpy(buffer, start, read); + fFontFileStream->ReleaseFileFragment(fragmentLock); + fPos = fileSize; + return read; + } + + return 0; +} + +bool SkDWriteFontFileStream::isAtEnd() const { + return fPos == this->getLength(); +} + +bool SkDWriteFontFileStream::rewind() { + fPos = 0; + return true; +} + +SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const { + return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get())); +} + +size_t SkDWriteFontFileStream::getPosition() const { + return fPos; +} + +bool SkDWriteFontFileStream::seek(size_t position) { + size_t length = this->getLength(); + fPos = (position > length) ? length : position; + return true; +} + +bool SkDWriteFontFileStream::move(long offset) { + return seek(fPos + offset); +} + +SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const { + SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate()); + that->seek(fPos); + return that.detach(); +} + +size_t SkDWriteFontFileStream::getLength() const { + HRESULT hr = S_OK; UINT64 realFileSize = 0; hr = fFontFileStream->GetFileSize(&realFileSize); if (realFileSize > (std::numeric_limits<size_t>::max)()) { return 0; } - size_t fileSize = static_cast<size_t>(realFileSize); - if (fPos + size > fileSize) { - size_t read = fileSize - fPos; - hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock); - if (SUCCEEDED(hr)) { - memcpy(buffer, start, read); - fFontFileStream->ReleaseFileFragment(fragmentLock); - fPos = fileSize; - return read; - } - return 0; - } else { - //This means we were within bounds, but failed for some other reason. - return 0; - } + return static_cast<size_t>(realFileSize); } +const void* SkDWriteFontFileStream::getMemoryBase() { + if (fLockedMemory) { + return fLockedMemory; + } + + UINT64 fileSize; + HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size"); + HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock), + "Could not lock file fragment."); + return fLockedMemory; +} /////////////////////////////////////////////////////////////////////////////// // SkIDWriteFontFileStreamWrapper @@ -116,8 +141,7 @@ HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFile } SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream) - : fRefCount(1), fStream(stream) { - stream->ref(); + : fRefCount(1), fStream(SkRef(stream)) { } HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) { @@ -180,7 +204,7 @@ HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment( if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) { return E_FAIL; } - SkAutoTDeleteArray<uint8_t> streamData(new uint8_t[static_cast<size_t>(fragmentSize)]); + SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize)); if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) { return E_FAIL; } @@ -192,10 +216,7 @@ HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment( } void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { - if (NULL == fragmentContext) { - return; - } - delete [] fragmentContext; + sk_free(fragmentContext); } HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { diff --git a/src/utils/win/SkDWriteFontFileStream.h b/src/utils/win/SkDWriteFontFileStream.h index b214858e57..5a56290c14 100644 --- a/src/utils/win/SkDWriteFontFileStream.h +++ b/src/utils/win/SkDWriteFontFileStream.h @@ -19,13 +19,20 @@ * An SkStream backed by an IDWriteFontFileStream. * This allows Skia code to read an IDWriteFontFileStream. */ -class SkDWriteFontFileStream : public SkStream { +class SkDWriteFontFileStream : public SkStreamMemory { public: explicit SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream); virtual ~SkDWriteFontFileStream(); - virtual bool rewind() SK_OVERRIDE; virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; + virtual bool isAtEnd() const SK_OVERRIDE; + virtual bool rewind() SK_OVERRIDE; + virtual SkDWriteFontFileStream* duplicate() const SK_OVERRIDE; + virtual size_t getPosition() const SK_OVERRIDE; + virtual bool seek(size_t position) SK_OVERRIDE; + virtual bool move(long offset) SK_OVERRIDE; + virtual SkDWriteFontFileStream* fork() const SK_OVERRIDE; + virtual size_t getLength() const SK_OVERRIDE; virtual const void* getMemoryBase() SK_OVERRIDE; private: diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp index d0a8507241..8f38f46bea 100644 --- a/tests/StreamTest.cpp +++ b/tests/StreamTest.cpp @@ -7,6 +7,7 @@ */ #include "Test.h" #include "SkRandom.h" +#include "SkOSFile.h" #include "SkStream.h" #include "SkData.h" @@ -17,67 +18,6 @@ #define MAX_SIZE (256 * 1024) -static void random_fill(SkMWCRandom& rand, void* buffer, size_t size) { - char* p = (char*)buffer; - char* stop = p + size; - while (p < stop) { - *p++ = (char)(rand.nextU() >> 8); - } -} - -static void test_buffer(skiatest::Reporter* reporter) { - SkMWCRandom rand; - SkAutoMalloc am(MAX_SIZE * 2); - char* storage = (char*)am.get(); - char* storage2 = storage + MAX_SIZE; - - random_fill(rand, storage, MAX_SIZE); - - for (int sizeTimes = 0; sizeTimes < 100; sizeTimes++) { - int size = rand.nextU() % MAX_SIZE; - if (size == 0) { - size = MAX_SIZE; - } - for (int times = 0; times < 100; times++) { - int bufferSize = 1 + (rand.nextU() & 0xFFFF); - SkMemoryStream mstream(storage, size); - SkBufferStream bstream(&mstream, bufferSize); - - int bytesRead = 0; - while (bytesRead < size) { - int s = 17 + (rand.nextU() & 0xFFFF); - int ss = bstream.read(storage2, s); - REPORTER_ASSERT(reporter, ss > 0 && ss <= s); - REPORTER_ASSERT(reporter, bytesRead + ss <= size); - REPORTER_ASSERT(reporter, - memcmp(storage + bytesRead, storage2, ss) == 0); - bytesRead += ss; - } - REPORTER_ASSERT(reporter, bytesRead == size); - } - } -} - -static void TestRStream(skiatest::Reporter* reporter) { - static const char s[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - char copy[sizeof(s)]; - SkMWCRandom rand; - - for (int i = 0; i < 65; i++) { - char* copyPtr = copy; - SkMemoryStream mem(s, sizeof(s)); - SkBufferStream buff(&mem, i); - - do { - copyPtr += buff.read(copyPtr, rand.nextU() & 15); - } while (copyPtr < copy + sizeof(s)); - REPORTER_ASSERT(reporter, copyPtr == copy + sizeof(s)); - REPORTER_ASSERT(reporter, memcmp(s, copy, sizeof(s)) == 0); - } - test_buffer(reporter); -} - static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream, const void* src, size_t len, int repeat) { SkAutoSMalloc<256> storage(len); @@ -118,16 +58,20 @@ static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) { SkFILEStream stream(path.c_str()); REPORTER_ASSERT(reporter, stream.isValid()); test_loop_stream(reporter, &stream, s, 26, 100); + + SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate()); + test_loop_stream(reporter, stream2.get(), s, 26, 100); } -#ifndef SK_BUILD_FOR_WIN { - int fd = ::open(path.c_str(), O_RDONLY); - SkFDStream stream(fd, true); + FILE* file = ::fopen(path.c_str(), "rb"); + SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership); REPORTER_ASSERT(reporter, stream.isValid()); test_loop_stream(reporter, &stream, s, 26, 100); + + SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate()); + test_loop_stream(reporter, stream2.get(), s, 26, 100); } -#endif } static void TestWStream(skiatest::Reporter* reporter) { @@ -142,7 +86,6 @@ static void TestWStream(skiatest::Reporter* reporter) { dst[100*26] = '*'; ds.copyTo(dst); REPORTER_ASSERT(reporter, dst[100*26] == '*'); -// char* p = dst; for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); } @@ -210,7 +153,6 @@ static void TestNullData() { } static void TestStreams(skiatest::Reporter* reporter) { - TestRStream(reporter); TestWStream(reporter); TestPackedUInt(reporter); TestNullData(); |