Change SkStream.
authorbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 29 May 2013 13:43:31 +0000 (13:43 +0000)
committerbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 29 May 2013 13:43:31 +0000 (13:43 +0000)
https://codereview.chromium.org/15298009/

git-svn-id: http://skia.googlecode.com/svn/trunk@9312 2bbb7eff-a529-9590-31e7-b0007b416f81

15 files changed:
gyp/core.gypi
gyp/ports.gyp
include/core/SkOSFile.h
include/core/SkStream.h
src/core/SkData.cpp
src/core/SkFDStream.cpp [deleted file]
src/core/SkStream.cpp
src/ports/SkFontHost_fontconfig.cpp
src/ports/SkOSFile_none.cpp [new file with mode: 0644]
src/ports/SkOSFile_posix.cpp [new file with mode: 0644]
src/ports/SkOSFile_stdio.cpp
src/ports/SkOSFile_win.cpp [new file with mode: 0644]
src/utils/win/SkDWriteFontFileStream.cpp
src/utils/win/SkDWriteFontFileStream.h
tests/StreamTest.cpp

index d472c6d..ab73ede 100644 (file)
@@ -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',
index abbe16b..fc9bb9b 100644 (file)
@@ -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',
           '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',
           ],
index 8564d43..11330a0 100644 (file)
@@ -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);
 
index 310f939..31ed7bc 100644 (file)
 
 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;
 };
 
 /////////////////////////////////////////////////////////////////////////////////////////////
index e47bbce..32e0297 100644 (file)
@@ -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 (file)
index ed94229..0000000
+++ /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
index 74734e6..91de88a 100644 (file)
@@ -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()));
index f42ab3f..a5aef56 100644 (file)
@@ -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 (file)
index 0000000..e22d22e
--- /dev/null
@@ -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 (file)
index 0000000..c9da4db
--- /dev/null
@@ -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;
+}
index 40c8745..ad26c80 100644 (file)
@@ -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>
 #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 (file)
index 0000000..fdf9ca5
--- /dev/null
@@ -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;
+}
index 1569158..971fdb9 100644 (file)
@@ -8,6 +8,7 @@
 #include "SkTypes.h"
 #include "SkDWriteFontFileStream.h"
 #include "SkHRESULT.h"
+#include "SkTScopedComPtr.h"
 
 #include <dwrite.h>
 #include <limits>
 //  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) {
index b214858..5a56290 100644 (file)
  *  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:
index d0a8507..8f38f46 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include "Test.h"
 #include "SkRandom.h"
+#include "SkOSFile.h"
 #include "SkStream.h"
 #include "SkData.h"
 
 
 #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();