aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/core.gypi1
-rw-r--r--gyp/ports.gyp4
-rw-r--r--include/core/SkOSFile.h16
-rw-r--r--include/core/SkStream.h319
-rw-r--r--src/core/SkData.cpp99
-rw-r--r--src/core/SkFDStream.cpp104
-rw-r--r--src/core/SkStream.cpp285
-rw-r--r--src/ports/SkFontHost_fontconfig.cpp30
-rw-r--r--src/ports/SkOSFile_none.cpp18
-rw-r--r--src/ports/SkOSFile_posix.cpp63
-rw-r--r--src/ports/SkOSFile_stdio.cpp79
-rw-r--r--src/ports/SkOSFile_win.cpp99
-rw-r--r--src/utils/win/SkDWriteFontFileStream.cpp135
-rw-r--r--src/utils/win/SkDWriteFontFileStream.h11
-rw-r--r--tests/StreamTest.cpp76
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();