summaryrefslogtreecommitdiff
path: root/platform/windows/mupdfwinrt
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2014-09-09 16:31:31 -0700
committerMichael Vrhel <michael.vrhel@artifex.com>2014-09-09 16:39:41 -0700
commit7ea99e3a8951e265d1437a77dcfee069de0edf76 (patch)
tree8e113fea67931064e2a9338d67b26aaabab27512 /platform/windows/mupdfwinrt
parent8a9519f2183b64fe220bcb1f6acedbe6acc190cd (diff)
downloadmupdf-7ea99e3a8951e265d1437a77dcfee069de0edf76.tar.xz
Rename of winrt to windows due to presence on gsview in this folder.
The contents of this folder will contain both winrt and gsview projects which are shared in a common visual studio 2013 solution.
Diffstat (limited to 'platform/windows/mupdfwinrt')
-rw-r--r--platform/windows/mupdfwinrt/Cache.cpp120
-rw-r--r--platform/windows/mupdfwinrt/Cache.h38
-rw-r--r--platform/windows/mupdfwinrt/ContentItem.cpp11
-rw-r--r--platform/windows/mupdfwinrt/ContentItem.h58
-rw-r--r--platform/windows/mupdfwinrt/Links.cpp12
-rw-r--r--platform/windows/mupdfwinrt/Links.h88
-rw-r--r--platform/windows/mupdfwinrt/muctx.cpp895
-rw-r--r--platform/windows/mupdfwinrt/muctx.h123
-rw-r--r--platform/windows/mupdfwinrt/mudocument.cpp470
-rw-r--r--platform/windows/mupdfwinrt/mudocument.h55
-rw-r--r--platform/windows/mupdfwinrt/mupdfwinrt.vcxproj249
-rw-r--r--platform/windows/mupdfwinrt/mupdfwinrt.vcxproj.filters27
-rw-r--r--platform/windows/mupdfwinrt/pch.cpp6
-rw-r--r--platform/windows/mupdfwinrt/pch.h6
-rw-r--r--platform/windows/mupdfwinrt/status.h19
-rw-r--r--platform/windows/mupdfwinrt/utils.cpp28
-rw-r--r--platform/windows/mupdfwinrt/utils.h7
17 files changed, 2212 insertions, 0 deletions
diff --git a/platform/windows/mupdfwinrt/Cache.cpp b/platform/windows/mupdfwinrt/Cache.cpp
new file mode 100644
index 00000000..b129710f
--- /dev/null
+++ b/platform/windows/mupdfwinrt/Cache.cpp
@@ -0,0 +1,120 @@
+#include "pch.h"
+#include "Cache.h"
+
+Cache::Cache(void)
+{
+ this->size = 0;
+ this->head = NULL;
+ this->tail = NULL;
+}
+
+Cache::~Cache(void)
+{
+}
+
+void Cache::Empty(fz_context *mu_ctx)
+{
+ if (this != nullptr) {
+ cache_entry_t *curr_entry = this->head;
+
+ while (curr_entry != NULL)
+ {
+ cache_entry_t *old_entry = curr_entry;
+ curr_entry = old_entry->next;
+ fz_drop_display_list(mu_ctx, old_entry->dlist);
+
+ delete old_entry;
+ }
+ this->size = 0;
+ this->head = NULL;
+ this->tail = NULL;
+ }
+}
+
+void Cache::Add(int value, int width_in, int height_in, fz_display_list *dlist,
+ fz_context *mu_ctx)
+{
+ std::lock_guard<std::mutex> lock(cache_lock);
+
+ /* If full, then delete the tail */
+ if (size >= MAX_DISPLAY_CACHE_SIZE)
+ {
+ cache_entry_t *curr_entry = this->tail;
+ cache_entry_t *prev_entry = curr_entry->prev;
+
+ if (prev_entry != NULL)
+ prev_entry->next = NULL;
+ else
+ head = NULL;
+
+ tail = prev_entry;
+
+ /* Decrement the caches rc of this list */
+ fz_drop_display_list(mu_ctx, curr_entry->dlist);
+ delete curr_entry;
+ size--;
+ }
+
+ /* Make a new entry and stick at head */
+ cache_entry_t *new_entry = new cache_entry_t;
+
+ new_entry->dlist = dlist;
+ new_entry->index = value;
+ new_entry->width = width_in;
+ new_entry->height = height_in;
+ new_entry->prev = NULL;
+ if (head == NULL)
+ {
+ new_entry->next = NULL;
+ head = new_entry;
+ tail = new_entry;
+ }
+ else
+ {
+ new_entry->next = head;
+ head->prev = new_entry;
+ head = new_entry;
+ }
+ size++;
+ /* We are going to use this item now */
+ fz_keep_display_list(mu_ctx, new_entry->dlist);
+}
+
+fz_display_list* Cache::Use(int value, int *width_out, int *height_out, fz_context *mu_ctx)
+{
+ std::lock_guard<std::mutex> lock(cache_lock);
+ cache_entry_t *curr_entry = this->head;
+
+ while (curr_entry != NULL)
+ {
+ if (curr_entry->index == value)
+ break;
+ curr_entry = curr_entry->next;
+ }
+ if (curr_entry != NULL)
+ {
+ fz_keep_display_list(mu_ctx, curr_entry->dlist);
+ /* Move this to the front */
+ if (curr_entry != head)
+ {
+ cache_entry_t *prev_entry = curr_entry->prev;
+ cache_entry_t *next_entry = curr_entry->next;
+ prev_entry->next = next_entry;
+
+ if (next_entry != NULL)
+ next_entry->prev = prev_entry;
+ else
+ tail = prev_entry;
+
+ curr_entry->prev = NULL;
+ curr_entry->next = head;
+ head->prev = curr_entry;
+ head = curr_entry;
+ }
+ *width_out = curr_entry->width;
+ *height_out = curr_entry->height;
+ return curr_entry->dlist;
+ }
+ else
+ return NULL;
+}
diff --git a/platform/windows/mupdfwinrt/Cache.h b/platform/windows/mupdfwinrt/Cache.h
new file mode 100644
index 00000000..e8c9801d
--- /dev/null
+++ b/platform/windows/mupdfwinrt/Cache.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <mutex>
+extern "C" {
+ #include "mupdf/fitz.h"
+}
+
+#define MAX_DISPLAY_CACHE_SIZE 3
+
+typedef struct cache_entry_s cache_entry_t;
+
+struct cache_entry_s
+{
+ int number;
+ int width;
+ int height;
+ fz_display_list *dlist;
+ cache_entry_t *next;
+ cache_entry_t *prev;
+ int index;
+};
+
+class Cache
+{
+private:
+ int size;
+ cache_entry_t *head;
+ cache_entry_t *tail;
+ std::mutex cache_lock;
+
+public:
+ Cache(void);
+ ~Cache(void);
+ void GetSize(int *width, int *height);
+ fz_display_list* Use(int value, int *width, int *height, fz_context *mu_ctx);
+ void Add(int value, int width, int height, fz_display_list *dlist, fz_context *mu_ctx);
+ void Empty(fz_context *mu_ctx);
+};
diff --git a/platform/windows/mupdfwinrt/ContentItem.cpp b/platform/windows/mupdfwinrt/ContentItem.cpp
new file mode 100644
index 00000000..eff1f58b
--- /dev/null
+++ b/platform/windows/mupdfwinrt/ContentItem.cpp
@@ -0,0 +1,11 @@
+#include "pch.h"
+#include "ContentItem.h"
+
+using namespace mupdfwinrt;
+
+ContentItem::ContentItem(void)
+{
+ StringOrig = nullptr;
+ StringMargin = nullptr;
+ Page = 0;
+}
diff --git a/platform/windows/mupdfwinrt/ContentItem.h b/platform/windows/mupdfwinrt/ContentItem.h
new file mode 100644
index 00000000..7077127d
--- /dev/null
+++ b/platform/windows/mupdfwinrt/ContentItem.h
@@ -0,0 +1,58 @@
+#pragma once
+
+using namespace Platform; /* For String */
+
+namespace mupdfwinrt {
+ [Windows::UI::Xaml::Data::Bindable]
+ public ref class ContentItem sealed
+ {
+ private:
+ int page;
+ String^ string_orig;
+ String^ string_margin;
+
+ public:
+ ContentItem(void);
+
+ property int Page
+ {
+ int get()
+ {
+ return (page);
+ }
+
+ void set(int value)
+ {
+ if (value < 0)
+ throw ref new Platform::InvalidArgumentException();
+ page = value;
+ }
+ }
+
+ property String^ StringOrig
+ {
+ String^ get()
+ {
+ return (string_orig);
+ }
+
+ void set(String^ value)
+ {
+ string_orig = value;
+ }
+ }
+
+ property String^ StringMargin
+ {
+ String^ get()
+ {
+ return (string_margin);
+ }
+
+ void set(String^ value)
+ {
+ string_margin = value;
+ }
+ }
+ };
+}
diff --git a/platform/windows/mupdfwinrt/Links.cpp b/platform/windows/mupdfwinrt/Links.cpp
new file mode 100644
index 00000000..50db8ff2
--- /dev/null
+++ b/platform/windows/mupdfwinrt/Links.cpp
@@ -0,0 +1,12 @@
+#include "pch.h"
+#include "Links.h"
+#include "status.h"
+
+using namespace mupdfwinrt;
+
+Links::Links(void)
+{
+ this->uri = nullptr;
+ this->page_num = -1;
+ this->type = NOT_SET;
+}
diff --git a/platform/windows/mupdfwinrt/Links.h b/platform/windows/mupdfwinrt/Links.h
new file mode 100644
index 00000000..39ebfc0b
--- /dev/null
+++ b/platform/windows/mupdfwinrt/Links.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "utils.h"
+#include "status.h"
+
+using namespace Windows::Foundation;
+
+namespace mupdfwinrt
+{
+ public ref class Links sealed
+ {
+ private:
+ int type;
+ Point upper_left;
+ Point lower_right;
+ Windows::Foundation::Uri ^uri;
+ int page_num;
+ public:
+ Links(void);
+
+ property int Type
+ {
+ int get()
+ {
+ return (type);
+ }
+
+ void set(int value)
+ {
+ if (value > NOT_SET)
+ throw ref new Platform::InvalidArgumentException();
+ type = value;
+ }
+ }
+
+ property Point UpperLeft
+ {
+ Point get()
+ {
+ return upper_left;
+ }
+
+ void set(Point value)
+ {
+ upper_left = value;
+ }
+ }
+
+ property Point LowerRight
+ {
+ Point get()
+ {
+ return lower_right;
+ }
+
+ void set(Point value)
+ {
+ lower_right = value;
+ }
+ }
+
+ property int PageNum
+ {
+ int get()
+ {
+ return page_num;
+ }
+
+ void set(int value)
+ {
+ page_num = value;
+ }
+ }
+
+ property Windows::Foundation::Uri^ Uri
+ {
+ Windows::Foundation::Uri^ get()
+ {
+ return uri;
+ }
+
+ void set(Windows::Foundation::Uri^ value)
+ {
+ uri = value;
+ }
+ }
+ };
+}
diff --git a/platform/windows/mupdfwinrt/muctx.cpp b/platform/windows/mupdfwinrt/muctx.cpp
new file mode 100644
index 00000000..d5c34c80
--- /dev/null
+++ b/platform/windows/mupdfwinrt/muctx.cpp
@@ -0,0 +1,895 @@
+#pragma once
+
+#include "pch.h"
+#include "muctx.h"
+#include "Cache.h"
+#include <mutex>
+
+/* This class interfaces to mupdf API with minimal windows objects
+ * (other than the file streaming stuff) */
+static int textlen(fz_text_page *page);
+
+#ifdef _WINRT_DLL
+// Attempt to use t.wait()
+//#include <ppltasks.h>
+//using namespace concurrency;
+/* File streaming set up for WinRT */
+static int win_next_file(fz_stream *stm, int len)
+{
+ void *temp = stm->state;
+ win_stream_struct *state = reinterpret_cast <win_stream_struct*> (temp);
+ IRandomAccessStream^ Stream = state->stream;
+ unsigned char *buf = state->public_buffer;
+ unsigned long long curr_pos = Stream->Position;
+ unsigned long long length = Stream->Size;
+ DataReader^ local_reader = ref new DataReader(Stream);
+ if (local_reader == nullptr)
+ return 0;
+
+ // This does not work here. mupdf is not set up to wait for win_next_file
+ // to complete in an ansyn manner
+ //auto t = create_task(local_reader->LoadAsync(len));
+ //t.wait();
+ DataReaderLoadOperation^ result = local_reader->LoadAsync(len);
+ while (result->Status != AsyncStatus::Completed) {
+ }
+ result->GetResults();
+
+ /* First see what is available */
+ int curr_len2 = local_reader->UnconsumedBufferLength;
+ if (curr_len2 < len)
+ len = curr_len2;
+
+ /* And make sure that we have enough room */
+ if (len > sizeof(state->public_buffer))
+ len = sizeof(state->public_buffer);
+
+ Platform::Array<unsigned char>^ arrByte = ref new Platform::Array<unsigned char>(len);
+ if (arrByte == nullptr)
+ return 0;
+ local_reader->ReadBytes(arrByte);
+
+ memcpy(buf, arrByte->Data, len);
+ local_reader->DetachStream();
+
+ stm->rp = buf;
+ stm->wp = buf + len;
+ stm->pos += len;
+ if (len == 0)
+ return EOF;
+ return *stm->rp++;
+}
+
+static void win_seek_file(fz_stream *stm, int offset, int whence)
+{
+ void *temp = stm->state;
+ win_stream_struct *stream = reinterpret_cast <win_stream_struct*> (temp);
+ IRandomAccessStream^ Stream = stream->stream;
+ unsigned long long curr_pos = Stream->Position;
+ unsigned long long length = Stream->Size;
+ unsigned long long n;
+
+ if (whence == SEEK_END)
+ {
+ n = length + offset;
+ }
+ else if (whence == SEEK_CUR)
+ {
+ n = curr_pos + offset;
+ }
+ else if (whence == SEEK_SET)
+ {
+ n = offset;
+ }
+ Stream->Seek(n);
+ curr_pos = Stream->Position;
+ stm->pos = n;
+ stm->wp = stm->rp;
+}
+
+static void win_close_file(fz_context *ctx, void *state)
+{
+ win_stream_struct *win_stream = reinterpret_cast <win_stream_struct*> (state);
+ IRandomAccessStream^ stream = win_stream->stream;
+ delete stream;
+}
+
+status_t muctx::InitializeStream(IRandomAccessStream^ readStream, char *ext)
+{
+ win_stream.stream = readStream;
+ fz_stream *mu_stream = fz_new_stream(mu_ctx, 0, win_next_file, win_close_file, NULL);
+ mu_stream->seek = win_seek_file;
+ mu_stream->state = reinterpret_cast <void*> (&win_stream);
+
+ /* Now lets see if we can open the file */
+ fz_try(mu_ctx)
+ {
+ mu_doc = fz_open_document_with_stream(mu_ctx, ext, mu_stream);
+ }
+ fz_always(mu_ctx)
+ {
+ fz_close(mu_stream);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAILURE;
+ }
+ return S_ISOK;
+}
+#else
+status_t muctx::OpenDocument(char *filename)
+{
+ fz_try(mu_ctx)
+ {
+ this->mu_doc = fz_open_document(mu_ctx, filename);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAILURE;
+ }
+ return S_ISOK;
+}
+#endif
+
+/* mutext functions see mupdf readme for details */
+static void lock_mutex(void *user, int lock)
+{
+ LPCRITICAL_SECTION locks = (LPCRITICAL_SECTION)user;
+ EnterCriticalSection(&locks[lock]);
+}
+
+static void unlock_mutex(void *user, int lock)
+{
+ LPCRITICAL_SECTION locks = (LPCRITICAL_SECTION)user;
+ LeaveCriticalSection(&locks[lock]);
+}
+
+void muctx::CleanUp(void)
+{
+ fz_free_outline(mu_ctx, mu_outline);
+ fz_close_document(mu_doc);
+ page_cache->Empty(mu_ctx);
+ annot_cache->Empty(mu_ctx);
+ fz_free_context(mu_ctx);
+
+ delete page_cache;
+ delete annot_cache;
+ annot_cache = NULL;
+ page_cache = NULL;
+ this->mu_ctx = NULL;
+ this->mu_doc = NULL;
+ this->mu_outline = NULL;
+}
+
+void muctx::SetAA(int level)
+{
+ fz_set_aa_level(mu_ctx, level);
+}
+
+/* Set up the context, mutex and cookie */
+status_t muctx::InitializeContext()
+{
+ int i;
+
+ /* Get the mutexes set up */
+ for (i = 0; i < FZ_LOCK_MAX; i++)
+ InitializeCriticalSectionEx(&mu_criticalsec[i], 0, 0);
+ mu_locks.user = &mu_criticalsec[0];
+ mu_locks.lock = lock_mutex;
+ mu_locks.unlock = unlock_mutex;
+
+ /* Allocate the context */
+ this->mu_ctx = fz_new_context(NULL, &mu_locks, FZ_STORE_DEFAULT);
+ if (this->mu_ctx == NULL)
+ {
+ return E_OUTOFMEM;
+ }
+ else
+ {
+ fz_register_document_handlers(this->mu_ctx);
+ return S_ISOK;
+ }
+}
+
+/* Initializer */
+muctx::muctx(void)
+{
+ mu_ctx = NULL;
+ mu_doc = NULL;
+ mu_outline = NULL;
+ page_cache = new Cache();
+ annot_cache = new Cache();
+}
+
+/* Destructor */
+muctx::~muctx(void)
+{
+ fz_free_outline(mu_ctx, mu_outline);
+ fz_close_document(mu_doc);
+ page_cache->Empty(mu_ctx);
+ annot_cache->Empty(mu_ctx);
+ fz_free_context(mu_ctx);
+
+ mu_ctx = NULL;
+ mu_doc = NULL;
+ mu_outline = NULL;
+ delete page_cache;
+ page_cache = NULL;
+ delete annot_cache;
+ annot_cache = NULL;
+}
+
+/* Return the documents page count */
+int muctx::GetPageCount()
+{
+ if (this->mu_doc == NULL)
+ return -1;
+ else
+ return this->mu_doc->count_pages(this->mu_doc);
+}
+
+/* Get page size */
+int muctx::MeasurePage(int page_num, point_t *size)
+{
+ fz_rect rect;
+ fz_page *page = NULL;
+ fz_rect *bounds;
+
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ bounds = fz_bound_page(mu_doc, page, &rect);
+ size->X = bounds->x1 - bounds->x0;
+ size->Y = bounds->y1 - bounds->y0;
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_page(mu_doc, page);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAIL;
+ }
+ return 0;
+}
+
+/* Get page size */
+point_t muctx::MeasurePage(fz_page *page)
+{
+ point_t pageSize;
+ fz_rect rect;
+ fz_rect *bounds;
+
+ bounds = fz_bound_page(mu_doc, page, &rect);
+ pageSize.X = bounds->x1 - bounds->x0;
+ pageSize.Y = bounds->y1 - bounds->y0;
+
+ return pageSize;
+}
+
+void muctx::FlattenOutline(fz_outline *outline, int level,
+ sh_vector_content contents_vec)
+{
+ char indent[8*4+1];
+ if (level > 8)
+ level = 8;
+ memset(indent, ' ', level * 4);
+ indent[level * 4] = 0;
+
+ std::string indent_str = indent;
+ std::string str_indent;
+
+ while (outline)
+ {
+ if (outline->dest.kind == FZ_LINK_GOTO)
+ {
+ int page = outline->dest.ld.gotor.page;
+ if (page >= 0 && outline->title)
+ {
+ /* Add to the contents std:vec */
+ sh_content content_item(new content_t());
+ content_item->page = page;
+ content_item->string_orig = outline->title;
+ str_indent = content_item->string_orig;
+ str_indent.insert(0, indent_str);
+ content_item->string_margin = str_indent;
+ contents_vec->push_back(content_item);
+ }
+ }
+ FlattenOutline(outline->down, level + 1, contents_vec);
+ outline = outline->next;
+ }
+}
+
+int muctx::GetContents(sh_vector_content contents_vec)
+{
+ fz_outline *root = NULL;
+ int has_content = 0;
+
+ fz_var(root);
+ fz_try(mu_ctx)
+ {
+ root = fz_load_outline(mu_doc);
+ if (root != NULL)
+ {
+ has_content = 1;
+ FlattenOutline(root, 0, contents_vec);
+ }
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_outline(mu_ctx, root);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAIL;
+ }
+ return has_content;
+}
+
+int muctx::GetTextSearch(int page_num, char* needle, sh_vector_text texts_vec)
+{
+ fz_page *page = NULL;
+ fz_text_sheet *sheet = NULL;
+ fz_device *dev = NULL;
+ fz_text_page *text = NULL;
+ int hit_count = 0;
+ int k;
+
+ fz_var(page);
+ fz_var(sheet);
+ fz_var(dev);
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ sheet = fz_new_text_sheet(mu_ctx);
+ text = fz_new_text_page(mu_ctx);
+ dev = fz_new_text_device(mu_ctx, sheet, text);
+ fz_run_page(mu_doc, page, dev, &fz_identity, NULL);
+ fz_free_device(dev); /* Why does this need to be done here? Seems odd */
+ dev = NULL;
+ hit_count = fz_search_text_page(mu_ctx, text, needle, mu_hit_bbox, nelem(mu_hit_bbox));
+
+ for (k = 0; k < hit_count; k++)
+ {
+ sh_text text_search(new text_search_t());
+ text_search->upper_left.X = mu_hit_bbox[k].x0;
+ text_search->upper_left.Y = mu_hit_bbox[k].y0;
+ text_search->lower_right.X = mu_hit_bbox[k].x1;
+ text_search->lower_right.Y = mu_hit_bbox[k].y1;
+ texts_vec->push_back(text_search);
+ }
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_page(mu_doc, page);
+ fz_free_device(dev);
+ fz_free_text_sheet(mu_ctx, sheet);
+ fz_free_text_page(mu_ctx, text);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAIL;
+ }
+ return hit_count;
+}
+
+/* Get the links and pack into a smart pointer structure */
+unsigned int muctx::GetLinks(int page_num, sh_vector_link links_vec)
+{
+ fz_page *page = NULL;
+ fz_link *links = NULL;
+ int k = 0;
+ unsigned int num_links = 0;
+
+ fz_var(page);
+ fz_var(links);
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ links = fz_load_links(mu_doc, page);
+
+ fz_link *curr_link = links;
+ if (curr_link != NULL)
+ {
+ /* Get our smart pointer structure filled */
+ while (curr_link != NULL)
+ {
+ fz_rect curr_rect = curr_link->rect;
+ sh_link link(new document_link_t());
+
+ link->upper_left.X = curr_rect.x0;
+ link->upper_left.Y = curr_rect.y0;
+ link->lower_right.X = curr_rect.x1;
+ link->lower_right.Y = curr_rect.y1;
+
+ switch (curr_link->dest.kind)
+ {
+ case FZ_LINK_GOTO:
+
+ link->type = LINK_GOTO;
+ link->page_num = curr_link->dest.ld.gotor.page;
+ break;
+
+ case FZ_LINK_URI:
+ {
+ int lenstr = strlen(curr_link->dest.ld.uri.uri);
+ std::unique_ptr<char[]> uri(new char[lenstr + 1]);
+ strcpy_s(uri.get(), lenstr + 1, curr_link->dest.ld.uri.uri);
+ link->uri.swap(uri);
+ link->type = LINK_URI;
+ break;
+ }
+
+ default:
+ link->type = NOT_SET;
+
+ }
+ links_vec->push_back(link);
+ curr_link = curr_link->next;
+ num_links += 1;
+ }
+ }
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_page(mu_doc, page);
+ fz_drop_link(mu_ctx, links);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAIL;
+ }
+ return num_links;
+}
+
+fz_display_list * muctx::CreateAnnotationList(int page_num)
+{
+ fz_device *dev = NULL;
+ fz_page *page = NULL;
+ int width, height;
+
+ /* First see if we have this one in the cache */
+ fz_display_list *dlist = annot_cache->Use(page_num, &width, &height, mu_ctx);
+ if (dlist != NULL)
+ return dlist;
+
+ /* Apparently not, lets go ahead and create and add to cache */
+ fz_var(dev);
+ fz_var(page);
+ fz_var(dlist);
+
+ fz_try(mu_ctx)
+ {
+ fz_annot *annot;
+ page = fz_load_page(mu_doc, page_num);
+ annot = fz_first_annot(mu_doc, page);
+ if (annot != NULL)
+ {
+ /* Create display list */
+ dlist = fz_new_display_list(mu_ctx);
+ dev = fz_new_list_device(mu_ctx, dlist);
+
+ for (annot = fz_first_annot(mu_doc, page); annot; annot = fz_next_annot(mu_doc, annot))
+ fz_run_annot(mu_doc, page, annot, dev, &fz_identity, NULL);
+ annot_cache->Add(page_num, 0, 0, dlist, mu_ctx);
+ }
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_device(dev);
+ fz_free_page(mu_doc, page);
+ }
+ fz_catch(mu_ctx)
+ {
+ fz_drop_display_list(mu_ctx, dlist);
+ return NULL;
+ }
+ return dlist;
+}
+
+fz_display_list * muctx::CreateDisplayList(int page_num, int *width, int *height)
+{
+ fz_device *dev = NULL;
+ fz_page *page = NULL;
+ point_t page_size;
+
+ /* First see if we have this one in the cache */
+ fz_display_list *dlist = page_cache->Use(page_num, width, height, mu_ctx);
+ if (dlist != NULL)
+ return dlist;
+
+ /* Apparently not, lets go ahead and create and add to cache */
+ fz_var(dev);
+ fz_var(page);
+ fz_var(dlist);
+
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+
+ /* Create a new list */
+ dlist = fz_new_display_list(mu_ctx);
+ dev = fz_new_list_device(mu_ctx, dlist);
+ fz_run_page_contents(mu_doc, page, dev, &fz_identity, NULL);
+ page_size = MeasurePage(page);
+ *width = page_size.X;
+ *height = page_size.Y;
+ /* Add it to the cache and set that it is in use */
+ page_cache->Add(page_num, *width, *height, dlist, mu_ctx);
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_device(dev);
+ fz_free_page(mu_doc, page);
+ }
+ fz_catch(mu_ctx)
+ {
+ fz_drop_display_list(mu_ctx, dlist);
+ return NULL;
+ }
+ return dlist;
+}
+
+/* A special version which will create the display list AND get the information
+ that we need for various text selection tasks */
+fz_display_list * muctx::CreateDisplayListText(int page_num, int *width, int *height,
+ fz_text_page **text_out, int *length)
+{
+ fz_text_sheet *sheet = NULL;
+ fz_text_page *text = NULL;
+ fz_device *dev = NULL;
+ fz_device *textdev = NULL;
+ fz_page *page = NULL;
+
+ point_t page_size;
+ *length = 0;
+
+ /* First see if we have this one in the cache */
+ fz_display_list *dlist = page_cache->Use(page_num, width, height, mu_ctx);
+ if (dlist != NULL)
+ return dlist;
+
+ /* Apparently not, lets go ahead and create and add to cache */
+ fz_var(dev);
+ fz_var(textdev);
+ fz_var(page);
+ fz_var(dlist);
+ fz_var(sheet);
+ fz_var(text);
+
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ sheet = fz_new_text_sheet(mu_ctx);
+ text = fz_new_text_page(mu_ctx);
+
+ /* Create a new list */
+ dlist = fz_new_display_list(mu_ctx);
+ dev = fz_new_list_device(mu_ctx, dlist);
+
+ /* Deal with text device */
+ textdev = fz_new_text_device(mu_ctx, sheet, text);
+ fz_run_page(mu_doc, page, textdev, &fz_identity, NULL);
+
+ *length = text->len;
+ fz_free_device(textdev);
+ textdev = NULL;
+ *text_out = text;
+
+ fz_run_page_contents(mu_doc, page, dev, &fz_identity, NULL);
+ page_size = MeasurePage(page);
+ *width = page_size.X;
+ *height = page_size.Y;
+ /* Add it to the cache and set that it is in use */
+ page_cache->Add(page_num, *width, *height, dlist, mu_ctx);
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_device(dev);
+ fz_free_page(mu_doc, page);
+ fz_free_text_sheet(mu_ctx, sheet);
+
+ }
+ fz_catch(mu_ctx)
+ {
+ fz_drop_display_list(mu_ctx, dlist);
+ return NULL;
+ }
+ return dlist;
+}
+
+/* Render display list bmp_data buffer. No lock needed for this operation */
+status_t muctx::RenderPageMT(void *dlist, void *a_dlist, int page_width, int page_height,
+ unsigned char *bmp_data, int bmp_width, int bmp_height,
+ float scale, bool flipy, bool tile, point_t top_left,
+ point_t bottom_right)
+{
+ fz_device *dev = NULL;
+ fz_pixmap *pix = NULL;
+ fz_matrix ctm, *pctm = &ctm;
+ fz_context *ctx_clone = NULL;
+ fz_display_list *display_list = (fz_display_list*) dlist;
+ fz_display_list *annot_displaylist = (fz_display_list*) a_dlist;
+
+ ctx_clone = fz_clone_context(mu_ctx);
+
+ fz_var(dev);
+ fz_var(pix);
+ fz_var(display_list);
+ fz_var(annot_displaylist);
+
+ fz_try(ctx_clone)
+ {
+ pctm = fz_scale(pctm, scale, scale);
+ /* Flip on Y. */
+ if (flipy)
+ {
+ ctm.f = (float) page_height * ctm.d;
+ ctm.d = -ctm.d;
+ ctm.f += top_left.Y;
+ }
+ else
+ {
+ ctm.f -= top_left.Y;
+ }
+ ctm.e -= top_left.X;
+
+ pix = fz_new_pixmap_with_data(ctx_clone, fz_device_bgr(ctx_clone),
+ bmp_width, bmp_height, bmp_data);
+ fz_clear_pixmap_with_value(ctx_clone, pix, 255);
+ dev = fz_new_draw_device(ctx_clone, pix);
+ fz_run_display_list(display_list, dev, pctm, NULL, NULL);
+ if (annot_displaylist != NULL)
+ fz_run_display_list(annot_displaylist, dev, pctm, NULL, NULL);
+
+ }
+ fz_always(ctx_clone)
+ {
+ fz_free_device(dev);
+ fz_drop_pixmap(ctx_clone, pix);
+ fz_drop_display_list(ctx_clone, display_list);
+ fz_drop_display_list(ctx_clone, annot_displaylist);
+ }
+ fz_catch(ctx_clone)
+ {
+ fz_free_context(ctx_clone);
+ return E_FAILURE;
+ }
+ fz_free_context(ctx_clone);
+ return S_ISOK;
+}
+
+/* Render page_num to size width by height into bmp_data buffer. Lock needed. */
+status_t muctx::RenderPage(int page_num, unsigned char *bmp_data, int bmp_width,
+ int bmp_height, float scale, bool flipy)
+{
+ fz_device *dev = NULL;
+ fz_pixmap *pix = NULL;
+ fz_page *page = NULL;
+ fz_matrix ctm, *pctm = &ctm;
+ point_t page_size;
+
+ fz_var(dev);
+ fz_var(pix);
+ fz_var(page);
+
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ page_size = MeasurePage(page);
+ pctm = fz_scale(pctm, scale, scale);
+ /* Flip on Y */
+ if (flipy)
+ {
+ ctm.f = bmp_height;
+ ctm.d = -ctm.d;
+ }
+ pix = fz_new_pixmap_with_data(mu_ctx, fz_device_bgr(mu_ctx), bmp_width,
+ bmp_height, bmp_data);
+ fz_clear_pixmap_with_value(mu_ctx, pix, 255);
+ dev = fz_new_draw_device(mu_ctx, pix);
+ fz_run_page(mu_doc, page, dev, pctm, NULL);
+
+ fz_annot *annot;
+ for (annot = fz_first_annot(mu_doc, page); annot; annot = fz_next_annot(mu_doc, annot))
+ fz_run_annot(mu_doc, page, annot, dev, &fz_identity, NULL);
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_device(dev);
+ fz_drop_pixmap(mu_ctx, pix);
+ fz_free_page(mu_doc, page);
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAILURE;
+ }
+ return S_ISOK;
+}
+
+bool muctx::RequiresPassword(void)
+{
+ return fz_needs_password(mu_doc) != 0;
+}
+
+bool muctx::ApplyPassword(char* password)
+{
+ return fz_authenticate_password(mu_doc, password) != 0;
+}
+
+std::string muctx::GetText(int page_num, int type)
+{
+ fz_output *out = NULL;
+ fz_device *dev = NULL;
+ fz_page *page = NULL;
+ fz_text_sheet *sheet = NULL;
+ fz_text_page *text = NULL;
+ fz_buffer *buf = NULL;
+ std::string output;
+
+ fz_var(dev);
+ fz_var(page);
+ fz_var(sheet);
+ fz_var(text);
+ fz_var(buf);
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ sheet = fz_new_text_sheet(mu_ctx);
+ text = fz_new_text_page(mu_ctx);
+ dev = fz_new_text_device(mu_ctx, sheet, text);
+ fz_run_page(mu_doc, page, dev, &fz_identity, NULL);
+ fz_free_device(dev);
+ dev = NULL;
+ fz_analyze_text(mu_ctx, sheet, text);
+ buf = fz_new_buffer(mu_ctx, 256);
+ out = fz_new_output_with_buffer(mu_ctx, buf);
+ if (type == HTML)
+ {
+ fz_print_text_page_html(mu_ctx, out, text);
+ }
+ else if (type == XML)
+ {
+ fz_print_text_page_xml(mu_ctx, out, text);
+ }
+ else
+ {
+ fz_print_text_page(mu_ctx, out, text);
+ }
+ output = std::string(((char*)buf->data));
+ }
+ fz_always(mu_ctx)
+ {
+ fz_free_device(dev);
+ fz_free_page(mu_doc, page);
+ fz_free_text_sheet(mu_ctx, sheet);
+ fz_free_text_page(mu_ctx, text);
+ fz_drop_buffer(mu_ctx, buf);
+ }
+ fz_catch(mu_ctx)
+ {
+ return nullptr;
+ }
+ return output;
+}
+
+void muctx::ReleaseText(void *text)
+{
+ fz_text_page *text_page = (fz_text_page*) text;
+ fz_free_text_page(mu_ctx, text_page);
+}
+
+/* To do: banding */
+status_t muctx::SavePage(char *filename, int page_num, int resolution, int type,
+ bool append)
+{
+ float zoom;
+ fz_matrix ctm;
+ fz_rect bounds, tbounds;
+ FILE *file = NULL;
+ fz_output *out = NULL;
+ fz_device *dev = NULL;
+ int width, height;
+ fz_display_list *dlist = NULL;
+ fz_display_list *annot_dlist = NULL;
+ fz_page *page = NULL;
+ bool valid = true;
+ fz_pixmap *pix = NULL;
+ fz_irect ibounds;
+
+ fz_var(dev);
+ fz_var(page);
+ fz_var(dlist);
+ fz_var(annot_dlist);
+ fz_var(pix);
+
+ fz_try(mu_ctx)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ fz_bound_page(mu_doc, page, &bounds);
+ zoom = resolution / 72;
+ fz_scale(&ctm, zoom, zoom);
+ tbounds = bounds;
+ fz_transform_rect(&tbounds, &ctm);
+ fz_round_rect(&ibounds, &tbounds);
+
+ /* First see if we have this one in the cache */
+ dlist = page_cache->Use(page_num, &width, &height, mu_ctx);
+ annot_dlist = annot_cache->Use(page_num, &width, &height, mu_ctx);
+
+ if (type == SVG_OUT)
+ {
+ file = fopen(filename, "wb");
+ if (file == NULL)
+ fz_throw(mu_ctx, FZ_ERROR_GENERIC, "cannot open file '%s'", filename);
+ out = fz_new_output_with_file(mu_ctx, file);
+
+ dev = fz_new_svg_device(mu_ctx, out, tbounds.x1 - tbounds.x0, tbounds.y1 - tbounds.y0);
+ if (dlist != NULL)
+ fz_run_display_list(dlist, dev, &ctm, &tbounds, NULL);
+ else
+ fz_run_page(mu_doc, page, dev, &ctm, NULL);
+ if (annot_dlist != NULL)
+ fz_run_display_list(annot_dlist, dev, &ctm, &tbounds, NULL);
+ else
+ {
+ fz_annot *annot;
+ for (annot = fz_first_annot(mu_doc, page); annot; annot = fz_next_annot(mu_doc, annot))
+ fz_run_annot(mu_doc, page, annot, dev, &fz_identity, NULL);
+ }
+ }
+ else
+ {
+ pix = fz_new_pixmap_with_bbox(mu_ctx, fz_device_rgb(mu_ctx), &ibounds);
+ fz_pixmap_set_resolution(pix, resolution);
+ fz_clear_pixmap_with_value(mu_ctx, pix, 255);
+ dev = fz_new_draw_device(mu_ctx, pix);
+ if (dlist != NULL)
+ fz_run_display_list(dlist, dev, &ctm, &tbounds, NULL);
+ else
+ fz_run_page(mu_doc, page, dev, &ctm, NULL);
+ if (annot_dlist != NULL)
+ fz_run_display_list(annot_dlist, dev, &ctm, &tbounds, NULL);
+ else
+ {
+ fz_annot *annot;
+ for (annot = fz_first_annot(mu_doc, page); annot; annot = fz_next_annot(mu_doc, annot))
+ fz_run_annot(mu_doc, page, annot, dev, &fz_identity, NULL);
+ }
+ switch (type)
+ {
+ case PNM_OUT:
+ fz_write_pnm(mu_ctx, pix, filename);
+ break;
+ case PCL_OUT: /* This can do multi-page */
+ fz_pcl_options options;
+ fz_pcl_preset(mu_ctx, &options, "ljet4");
+ fz_write_pcl(mu_ctx, pix, filename, append, &options);
+ break;
+ case PWG_OUT: /* This can do multi-page */
+ fz_write_pwg(mu_ctx, pix, filename, append, NULL);
+ break;
+ }
+ }
+ }
+ fz_always(mu_ctx)
+ {
+ if (pix != NULL)
+ fz_drop_pixmap(mu_ctx, pix);
+ fz_free_device(dev);
+ fz_free_page(mu_doc, page);
+ if (dlist != NULL)
+ fz_drop_display_list(mu_ctx, dlist);
+ if (out != NULL)
+ {
+ fz_close_output(out);
+ fclose(file);
+ }
+ }
+ fz_catch(mu_ctx)
+ {
+ return E_FAILURE;
+ }
+ return S_ISOK;
+} \ No newline at end of file
diff --git a/platform/windows/mupdfwinrt/muctx.h b/platform/windows/mupdfwinrt/muctx.h
new file mode 100644
index 00000000..16c44cd1
--- /dev/null
+++ b/platform/windows/mupdfwinrt/muctx.h
@@ -0,0 +1,123 @@
+#pragma once
+
+#include <memory>
+#include <functional>
+#include <vector>
+#include <windows.h>
+#include "status.h"
+#include "Cache.h"
+extern "C" {
+#include "mupdf/fitz.h"
+#include "mupdf/pdf-tools.h"
+}
+
+
+#define MAX_SEARCH 500
+
+enum { SVG_OUT, PNM_OUT, PCL_OUT, PWG_OUT };
+enum { HTML = 0, XML, TEXT };
+
+typedef struct point_s
+{
+ double X;
+ double Y;
+} point_t;
+
+/* Links */
+typedef struct document_link_s
+{
+ link_t type;
+ point_t upper_left;
+ point_t lower_right;
+ std::unique_ptr<char[]> uri;
+ int page_num;
+} document_link_t;
+#define sh_link std::shared_ptr<document_link_t>
+#define sh_vector_link std::shared_ptr<std::vector<sh_link>>
+
+/* Text Search */
+typedef struct text_search_s
+{
+ point_t upper_left;
+ point_t lower_right;
+} text_search_t;
+#define sh_text std::shared_ptr<text_search_t>
+#define sh_vector_text std::shared_ptr<std::vector<sh_text>>
+
+/* Content Results */
+typedef struct content_s
+{
+ int page;
+ std::string string_orig;
+ std::string string_margin;
+} content_t;
+#define sh_content std::shared_ptr<content_t>
+#define sh_vector_content std::shared_ptr<std::vector<sh_content>>
+
+#ifdef _WINRT_DLL
+using namespace Windows::Storage::Streams;
+using namespace Windows::Foundation;
+
+typedef struct win_stream_struct_s
+{
+ IRandomAccessStream^ stream;
+ unsigned char public_buffer[4096];
+} win_stream_struct;
+#else
+typedef struct win_stream_struct_s
+{
+ char* stream;
+} win_stream_struct;
+#endif
+
+class muctx
+{
+private:
+ CRITICAL_SECTION mu_criticalsec[FZ_LOCK_MAX];
+ win_stream_struct win_stream;
+ fz_locks_context mu_locks;
+ fz_context *mu_ctx;
+ fz_document *mu_doc;
+ fz_outline *mu_outline;
+ fz_rect mu_hit_bbox[MAX_SEARCH];
+ void FlattenOutline(fz_outline *outline, int level,
+ sh_vector_content contents_vec);
+ Cache *page_cache;
+ Cache *annot_cache;
+
+public:
+ muctx(void);
+ ~muctx(void);
+ void CleanUp(void);
+ int GetPageCount();
+ status_t InitializeContext();
+ status_t RenderPage(int page_num, unsigned char *bmp_data, int bmp_width,
+ int bmp_height, float scale, bool flipy);
+ status_t RenderPageMT(void *dlist, void *a_dlist, int page_width, int page_height,
+ unsigned char *bmp_data, int bmp_width, int bmp_height,
+ float scale, bool flipy, bool tile, point_t top_left,
+ point_t bottom_right);
+ fz_display_list* CreateDisplayList(int page_num, int *width, int *height);
+ fz_display_list * CreateDisplayListText(int page_num, int *width,
+ int *height, fz_text_page **text, int *length);
+ fz_display_list * CreateAnnotationList(int page_num);
+ int MeasurePage(int page_num, point_t *size);
+ point_t MeasurePage(fz_page *page);
+ unsigned int GetLinks(int page_num, sh_vector_link links_vec);
+ void SetAA(int level);
+ int GetTextSearch(int page_num, char* needle, sh_vector_text texts_vec);
+ int GetContents(sh_vector_content contents_vec);
+ std::string GetText(int page_num, int type);
+ void ReleaseText(void *text);
+ bool RequiresPassword(void);
+ bool ApplyPassword(char* password);
+ status_t SavePage(char *filename, int pagenum, int resolution, int type,
+ bool append);
+
+#ifdef _WINRT_DLL
+ status_t InitializeStream(IRandomAccessStream^ readStream, char *ext);
+#else
+ status_t OpenDocument(char *filename);
+#endif
+
+};
diff --git a/platform/windows/mupdfwinrt/mudocument.cpp b/platform/windows/mupdfwinrt/mudocument.cpp
new file mode 100644
index 00000000..060144b3
--- /dev/null
+++ b/platform/windows/mupdfwinrt/mudocument.cpp
@@ -0,0 +1,470 @@
+// mudocument.cpp
+
+/* This file contains the interface between the muctx class, which
+ implements the mupdf calls and the WinRT objects enabling calling from
+ C#, C++, Visual Basic, JavaScript applications */
+
+#include "pch.h"
+#include "mudocument.h"
+#include "status.h"
+#include "utils.h"
+
+using namespace mupdfwinrt;
+using namespace concurrency;
+using namespace Platform::Collections;
+
+mudocument::mudocument()
+{
+ this->mu_object.InitializeContext();
+ this->links = nullptr;
+}
+
+bool mudocument::RequiresPassword()
+{
+ return mu_object.RequiresPassword();
+}
+
+bool mudocument::ApplyPassword(String^ password)
+{
+ char* pass_char = String_to_char(password);
+ bool ok = mu_object.ApplyPassword(pass_char);
+ delete []pass_char;
+ return ok;
+}
+
+void mudocument::CleanUp()
+{
+ this->mu_object.CleanUp();
+}
+
+int mudocument::GetNumPages()
+{
+ return this->mu_object.GetPageCount();
+}
+
+Point mudocument::GetPageSize(int page_num)
+{
+ Point size_out;
+ point_t size;
+
+ mutex_lock.lock();
+ int code = this->mu_object.MeasurePage(page_num, &size);
+ mutex_lock.unlock();
+ if (code < 0)
+ throw ref new Exception(code, ref new String(L"Get Page Size Failed"));
+
+ size_out.X = size.X;
+ size_out.Y = size.Y;
+ return size_out;
+}
+
+Windows::Foundation::IAsyncOperation<int>^ mudocument::OpenFileAsync(StorageFile^ file)
+{
+ return create_async([this, file]()
+ {
+ String^ filetype = file->FileType;
+ const wchar_t *w = filetype->Data();
+ int cb = WideCharToMultiByte(CP_UTF8, 0, w, -1, nullptr, 0, nullptr, nullptr);
+ char* name = new char[cb];
+
+ WideCharToMultiByte(CP_UTF8, 0, w ,-1 ,name ,cb ,nullptr, nullptr);
+ char *ext = strrchr(name, '.');
+
+ auto t = create_task(file->OpenAsync(FileAccessMode::Read));
+
+ return t.then([this, file, ext](task<IRandomAccessStream^> task)
+ {
+ try
+ {
+ IRandomAccessStream^ readStream = task.get();
+ UINT64 const size = readStream->Size;
+
+ if (size <= MAXUINT32)
+ {
+ status_t code = this->mu_object.InitializeStream(readStream, ext);
+ if (code != S_ISOK)
+ delete readStream;
+ return (int) code;
+ }
+ else
+ {
+ delete readStream;
+ return (int) E_FAILURE;
+ }
+ }
+ catch(COMException^ ex) {
+ throw ref new FailureException("Open File Failed");
+ }
+ });
+ });
+}
+
+/* Header info for bmp stream so that we can use the image brush */
+static void Prepare_bmp(int width, int height, DataWriter ^dw)
+{
+ int row_size = width * 4;
+ int bmp_size = row_size * height + 54;
+
+ dw->WriteString("BM");
+ dw->ByteOrder = ByteOrder::LittleEndian;
+ dw->WriteInt32(bmp_size);
+ dw->WriteInt16(0);
+ dw->WriteInt16(0);
+ dw->WriteInt32(54);
+ dw->WriteInt32(40);
+ dw->WriteInt32(width);
+ dw->WriteInt32(height);
+ dw->WriteInt16(1);
+ dw->WriteInt16(32);
+ dw->WriteInt32(0);
+ dw->WriteInt32(row_size * height);
+ dw->WriteInt32(2835);
+ dw->WriteInt32(2835);
+ dw->WriteInt32(0);
+ dw->WriteInt32(0);
+}
+
+/* Do the search through the pages with an async task with progress callback */
+Windows::Foundation::IAsyncOperationWithProgress<int, double>^
+ mudocument::SearchDocumentWithProgressAsync(String^ textToFind, int dir,
+ int start_page, int num_pages)
+{
+ return create_async([this, textToFind, dir, start_page, num_pages]
+ (progress_reporter<double> reporter) -> int
+ {
+ double progress;
+ int box_count, result;
+
+ for (int i = start_page; i >= 0 && i < num_pages; i += dir)
+ {
+ box_count = this->ComputeTextSearch(textToFind, i);
+ result = i;
+ if (dir == SEARCH_FORWARD)
+ {
+ progress = 100.0 * (double) (i + 1) / (double) num_pages;
+ }
+ else
+ {
+ progress = 100.0 * (double) (num_pages - i) / (double) num_pages;
+ }
+ /* We could have it only update with certain percentage changes but
+ we are just looping over the pages here so it is not too bad */
+ reporter.report(progress);
+
+ if (is_task_cancellation_requested())
+ {
+ // Cancel the current task.
+ cancel_current_task();
+ }
+
+ if (box_count > 0)
+ {
+ return result;
+ }
+ if (is_task_cancellation_requested())
+ {
+ }
+ }
+ reporter.report(100.0);
+ if (box_count == 0)
+ return TEXT_NOT_FOUND;
+ else
+ return result;
+ });
+}
+
+/* Pack the page into a bitmap. This is used in the DirectX code for printing
+ not in the xaml related code. It is also used by the thumbnail creation
+ thread to ensure that the thumbs are created in order and we don't create
+ thousands of threads */
+int mudocument::RenderPageBitmapSync(int page_num, int bmp_width, int bmp_height,
+ float scale, bool use_dlist, bool flipy, bool tile,
+ Point top_left, Point bottom_right,
+ Array<unsigned char>^* bit_map)
+{
+ status_t code;
+ /* Allocate space for bmp */
+ Array<unsigned char>^ bmp_data =
+ ref new Array<unsigned char>(bmp_height * 4 * bmp_width);
+
+ if (bmp_data == nullptr)
+ {
+ *bit_map = nullptr;
+ return E_OUTOFMEM;
+ }
+
+ if (use_dlist)
+ {
+ void *dlist;
+ void *annotlist;
+ int page_height;
+ int page_width;
+
+ mutex_lock.lock();
+ /* This lock will keep out issues in mupdf as well as race conditions
+ in the page cache */
+ dlist = (void*) mu_object.CreateDisplayList(page_num, &page_width,
+ &page_height);
+ annotlist = (void*)mu_object.CreateAnnotationList(page_num);
+ /* Rendering of display list can occur with other threads so unlock */
+ mutex_lock.unlock();
+ if (dlist == NULL)
+ {
+ *bit_map = nullptr;
+ return E_FAILURE;
+ }
+ code = mu_object.RenderPageMT(dlist, annotlist, page_width, page_height,
+ &(bmp_data[0]), bmp_width, bmp_height,
+ scale, flipy, tile, { top_left.X, top_left.Y },
+ { bottom_right.X, bottom_right.Y });
+ }
+ else
+ {
+ /* Not dealing with the case of tiling and no display list at this time. */
+ if (tile)
+ {
+ *bit_map = nullptr;
+ return E_FAILURE;
+ }
+ /* Rendering in immediate mode. Keep lock in place */
+ mutex_lock.lock();
+ code = mu_object.RenderPage(page_num, &(bmp_data[0]), bmp_width,
+ bmp_height, scale, flipy);
+ mutex_lock.unlock();
+ }
+ if (code != S_ISOK)
+ {
+ *bit_map = nullptr;
+ return E_FAILURE;
+ }
+
+ *bit_map = bmp_data;
+ return (int) code;
+}
+
+/* Pack the page into a bmp stream */
+Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^
+ mudocument::RenderPageAsync(int page_num, int bmp_width, int bmp_height,
+ bool use_dlist, float scale)
+{
+ return create_async([this, bmp_width, bmp_height, page_num, use_dlist, scale]
+ (cancellation_token ct) -> InMemoryRandomAccessStream^
+ {
+ /* Allocate space for bmp */
+ Array<unsigned char>^ bmp_data =
+ ref new Array<unsigned char>(bmp_height * 4 * bmp_width);
+ if (bmp_data == nullptr)
+ return nullptr;
+
+ /* Set up the memory stream */
+ InMemoryRandomAccessStream ^ras = ref new InMemoryRandomAccessStream();
+ if (ras == nullptr)
+ return nullptr;
+ DataWriter ^dw = ref new DataWriter(ras->GetOutputStreamAt(0));
+ if (dw == nullptr)
+ return nullptr;
+
+ status_t code;
+
+ /* Go ahead and write our header data into the memory stream */
+ Prepare_bmp(bmp_width, bmp_height, dw);
+
+ if (use_dlist)
+ {
+ void *dlist;
+ void *annotlist;
+ int page_height;
+ int page_width;
+
+ mutex_lock.lock();
+ /* This lock will keep out issues in mupdf as well as race conditions
+ in the page cache */
+ dlist = (void*) mu_object.CreateDisplayList(page_num, &page_width,
+ &page_height);
+ annotlist = (void*)mu_object.CreateAnnotationList(page_num);
+ mutex_lock.unlock();
+ if (dlist == NULL)
+ return nullptr;
+ /* Rendering of display list can occur with other threads so unlock */
+ code = mu_object.RenderPageMT(dlist, annotlist, page_width, page_height,
+ &(bmp_data[0]), bmp_width, bmp_height,
+ scale, true, false, { 0.0, 0.0 },
+ { (float) bmp_width, (float) bmp_height });
+ }
+ else
+ {
+ /* Rendering in immediate mode. Keep lock in place */
+ mutex_lock.lock();
+ code = mu_object.RenderPage(page_num, &(bmp_data[0]), bmp_width,
+ bmp_height, scale, true);
+ mutex_lock.unlock();
+ }
+ if (code != S_ISOK)
+ return nullptr;
+ /* Now the data into the memory stream */
+ dw->WriteBytes(bmp_data);
+ auto t = create_task(dw->StoreAsync());
+ t.wait();
+ /* Return raster stream */
+ return ras;
+ });
+}
+
+unsigned int mudocument::ComputeLinks(int page_num)
+{
+ /* We get back a standard smart pointer from muctx interface and go to WinRT
+ type here */
+ sh_vector_link link_smart_ptr_vec(new std::vector<sh_link>());
+ mutex_lock.lock();
+ unsigned int num_items = mu_object.GetLinks(page_num, link_smart_ptr_vec);
+ mutex_lock.unlock();
+ if (num_items == 0 || num_items == E_FAIL)
+ return 0;
+ /* Pack into winRT type*/
+ this->links = ref new Platform::Collections::Vector<Links^>();
+ if (this->links == nullptr)
+ return 0;
+ for (unsigned int k = 0; k < num_items; k++)
+ {
+ auto new_link = ref new Links();
+ if (new_link == nullptr)
+ {
+ this->links = nullptr;
+ return 0;
+ }
+ sh_link muctx_link = link_smart_ptr_vec->at(k);
+ new_link->LowerRight = { (float) muctx_link->lower_right.X, (float) muctx_link->lower_right.Y };
+ new_link->UpperLeft = { (float) muctx_link->upper_left.X, (float) muctx_link->upper_left.Y };
+ new_link->PageNum = muctx_link->page_num;
+ new_link->Type = muctx_link->type;
+ if (new_link->Type == LINK_URI)
+ {
+ String^ str = char_to_String(muctx_link->uri.get());
+ // The URI to launch
+ new_link->Uri = ref new Windows::Foundation::Uri(str);
+ if (new_link->Uri == nullptr)
+ {
+ this->links = nullptr;
+ return 0;
+ }
+ }
+ this->links->Append(new_link);
+ }
+ return num_items;
+}
+
+Links^ mudocument::GetLink(unsigned int k)
+{
+ if (k >= this->links->Size)
+ return nullptr;
+ return this->links->GetAt(k);
+}
+
+int mudocument::ComputeTextSearch(String^ text, int page_num)
+{
+ /* We get back a standard smart pointer from muctx interface and go to
+ * WinRT type here */
+ char* text_char = String_to_char(text);
+ sh_vector_text text_smart_ptr_vec(new std::vector<sh_text>());
+ int num_items;
+
+ mutex_lock.lock();
+ num_items = mu_object.GetTextSearch(page_num, text_char, text_smart_ptr_vec);
+ mutex_lock.unlock();
+
+ if (num_items == 0)
+ return 0;
+ /* Pack into winRT type*/
+ this->textsearch = ref new Platform::Collections::Vector<Links^>();
+ if (this->textsearch == nullptr)
+ return 0;
+ for (int k = 0; k < num_items; k++)
+ {
+ auto new_link = ref new Links();
+ if (new_link == nullptr)
+ {
+ this->textsearch = nullptr;
+ return 0;
+ }
+ sh_text muctx_text = text_smart_ptr_vec->at(k);
+ new_link->LowerRight = { (float) muctx_text->lower_right.X, (float) muctx_text->lower_right.Y };
+ new_link->UpperLeft = { (float) muctx_text->upper_left.X, (float) muctx_text->upper_left.Y };
+ new_link->Type = TEXTBOX;
+ this->textsearch->Append(new_link);
+ }
+ delete []text_char;
+ return num_items;
+}
+
+/* Return number of hits found on most recent page */
+int mudocument::TextSearchCount(void)
+{
+ if (this->textsearch != nullptr)
+ return this->textsearch->Size;
+ else
+ return 0;
+}
+
+/* Returns the kth item for a page after a text search query */
+Links^ mudocument::GetTextSearch(unsigned int k)
+{
+ if (k >= this->textsearch->Size)
+ return nullptr;
+ return this->textsearch->GetAt(k);
+}
+
+unsigned int mudocument::ComputeContents()
+{
+ /* We get back a standard smart pointer from muctx interface and go to
+ * WinRT type here */
+ sh_vector_content content_smart_ptr_vec(new std::vector<sh_content>());
+ int has_content;
+
+ mutex_lock.lock();
+ has_content = mu_object.GetContents(content_smart_ptr_vec);
+ mutex_lock.unlock();
+
+ if (!has_content)
+ return 0;
+ /* Pack into winRT type */
+ this->contents = ref new Platform::Collections::Vector<ContentItem^>();
+ if (this->contents == nullptr)
+ return 0;
+ unsigned int num_items = content_smart_ptr_vec->size();
+
+ for (unsigned int k = 0; k < num_items; k++)
+ {
+ auto new_content = ref new ContentItem();
+ if (new_content == nullptr)
+ {
+ this->contents = nullptr;
+ return 0;
+ }
+ sh_content muctx_content = content_smart_ptr_vec->at(k);
+ new_content->Page = muctx_content->page;
+ new_content->StringMargin = char_to_String(muctx_content->string_margin.c_str());
+ new_content->StringOrig = char_to_String(muctx_content->string_orig.c_str());
+ this->contents->Append(new_content);
+ }
+ return num_items;
+}
+
+ContentItem^ mudocument::GetContent(unsigned int k)
+{
+ if (k >= this->contents->Size)
+ return nullptr;
+ return this->contents->GetAt(k);
+}
+
+String^ mudocument::ComputeHTML(int page_num)
+{
+ String^ html = nullptr;
+ std::string html_cstr;
+
+ mutex_lock.lock();
+ html_cstr = mu_object.GetText(page_num, HTML);
+ mutex_lock.unlock();
+
+ html = char_to_String(html_cstr.c_str());
+ return html;
+}
diff --git a/platform/windows/mupdfwinrt/mudocument.h b/platform/windows/mupdfwinrt/mudocument.h
new file mode 100644
index 00000000..9ab37ed7
--- /dev/null
+++ b/platform/windows/mupdfwinrt/mudocument.h
@@ -0,0 +1,55 @@
+#pragma once
+
+/* This file contains the interface between the muctx class, which
+ implements the mupdf calls and the WinRT objects enabling calling from
+ C#, C++, and JavaScript applications */
+
+#include "muctx.h"
+#include "Links.h"
+#include "ppltasks.h"
+#include "ContentItem.h"
+#include <winnt.h>
+#include <collection.h>
+
+using namespace Windows::Storage;
+using namespace Platform;
+using namespace Concurrency;
+using namespace Platform::Collections;
+
+namespace mupdfwinrt
+{
+ public ref class mudocument sealed
+ {
+ private:
+ muctx mu_object;
+ std::mutex mutex_lock;
+ Platform::Collections::Vector<Links^>^ links;
+ Platform::Collections::Vector<Links^>^ textsearch;
+ Platform::Collections::Vector<ContentItem^>^ contents;
+ public:
+ mudocument();
+ void CleanUp();
+ Windows::Foundation::IAsyncOperation<int>^ OpenFileAsync(StorageFile^ file);
+ int GetNumPages(void);
+ Point GetPageSize(int page_num);
+ Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^
+ RenderPageAsync(int page_num, int width, int height,
+ bool use_dlist, float scale);
+ int RenderPageBitmapSync(int page_num, int bmp_width, int bmp_height,
+ float scale, bool use_dlist, bool flipy, bool tiling, Point top_left,
+ Point bottom_right, Array<unsigned char>^* bit_map);
+ Windows::Foundation::IAsyncOperationWithProgress<int, double>^
+ SearchDocumentWithProgressAsync(String^ textToFind, int dir,
+ int start_page, int num_pages);
+ String^ ComputeHTML(int page_num);
+ int ComputeTextSearch(String^ text, int page_num);
+ Links^ GetTextSearch(unsigned int k);
+ int TextSearchCount(void);
+ unsigned int ComputeContents(void);
+ ContentItem^ GetContent(unsigned int k);
+ unsigned int ComputeLinks(int page_num);
+ Links^ GetLink(unsigned int k);
+ bool RequiresPassword();
+ bool ApplyPassword(String^ password);
+ };
+}
diff --git a/platform/windows/mupdfwinrt/mupdfwinrt.vcxproj b/platform/windows/mupdfwinrt/mupdfwinrt.vcxproj
new file mode 100644
index 00000000..fa162f0e
--- /dev/null
+++ b/platform/windows/mupdfwinrt/mupdfwinrt.vcxproj
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM">
+ <Configuration>Release</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{9e6ab41d-09a7-45a6-a53b-1e4bf3ac5b33}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectName>mupdfwinrt</ProjectName>
+ <RootNamespace>mupdfwinrt</RootNamespace>
+ <DefaultLanguage>en-US</DefaultLanguage>
+ <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
+ <AppContainerApplication>true</AppContainerApplication>
+ <ApplicationType>Windows Store</ApplicationType>
+ <ApplicationTypeRevision>8.1</ApplicationTypeRevision>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <GenerateManifest>false</GenerateManifest>
+ <OutDir>..\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>..\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <GenerateManifest>false</GenerateManifest>
+ <OutDir>..\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>..\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <GenerateManifest>false</GenerateManifest>
+ <OutDir>..\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>..\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <GenerateManifest>false</GenerateManifest>
+ <OutDir>..\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>..\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <GenerateManifest>false</GenerateManifest>
+ <OutDir>..\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>..\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <GenerateManifest>false</GenerateManifest>
+ <OutDir>..\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>..\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>../../../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>../../../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>../../../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib;../$(Platform)/$(Configuration)/libmupdf-nov8_winRT.lib</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>../../../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib;../$(Platform)/$(Configuration)/libmupdf-nov8_winRT.lib</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>../../../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
+ <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>../../../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="Cache.h" />
+ <ClInclude Include="ContentItem.h" />
+ <ClInclude Include="muctx.h" />
+ <ClInclude Include="pch.h" />
+ <ClInclude Include="mudocument.h" />
+ <ClInclude Include="status.h" />
+ <ClInclude Include="utils.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Cache.cpp" />
+ <ClCompile Include="Links.cpp" />
+ <ClCompile Include="ContentItem.cpp" />
+ <ClCompile Include="muctx.cpp" />
+ <ClCompile Include="pch.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="mudocument.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/platform/windows/mupdfwinrt/mupdfwinrt.vcxproj.filters b/platform/windows/mupdfwinrt/mupdfwinrt.vcxproj.filters
new file mode 100644
index 00000000..99e37356
--- /dev/null
+++ b/platform/windows/mupdfwinrt/mupdfwinrt.vcxproj.filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Resources">
+ <UniqueIdentifier>16ec6626-1276-4cf1-b7af-8d28de2c8f75</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="pch.cpp" />
+ <ClCompile Include="mudocument.cpp" />
+ <ClCompile Include="muctx.cpp" />
+ <ClCompile Include="Links.cpp" />
+ <ClCompile Include="ContentItem.cpp" />
+ <ClCompile Include="utils.cpp" />
+ <ClCompile Include="Cache.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="pch.h" />
+ <ClInclude Include="mudocument.h" />
+ <ClInclude Include="muctx.h" />
+ <ClInclude Include="utils.h" />
+ <ClInclude Include="ContentItem.h" />
+ <ClInclude Include="Cache.h" />
+ <ClInclude Include="status.h" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/platform/windows/mupdfwinrt/pch.cpp b/platform/windows/mupdfwinrt/pch.cpp
new file mode 100644
index 00000000..01484ff5
--- /dev/null
+++ b/platform/windows/mupdfwinrt/pch.cpp
@@ -0,0 +1,6 @@
+//
+// pch.cpp
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/platform/windows/mupdfwinrt/pch.h b/platform/windows/mupdfwinrt/pch.h
new file mode 100644
index 00000000..f815ac97
--- /dev/null
+++ b/platform/windows/mupdfwinrt/pch.h
@@ -0,0 +1,6 @@
+//
+// pch.h
+// Header for standard system include files.
+//
+
+#pragma once
diff --git a/platform/windows/mupdfwinrt/status.h b/platform/windows/mupdfwinrt/status.h
new file mode 100644
index 00000000..9eea09aa
--- /dev/null
+++ b/platform/windows/mupdfwinrt/status.h
@@ -0,0 +1,19 @@
+#pragma once
+
+typedef enum {
+ S_ISOK = 0,
+ E_FAILURE = -1,
+ E_OUTOFMEM = -2,
+ E_NEEDPASSWORD = -3
+} status_t;
+
+typedef enum {
+ LINK_GOTO = 0,
+ LINK_URI,
+ TEXTBOX, /* Do double duty with this class */
+ NOT_SET,
+} link_t;
+
+#define SEARCH_FORWARD 1
+#define SEARCH_BACKWARD -1
+#define TEXT_NOT_FOUND -1
diff --git a/platform/windows/mupdfwinrt/utils.cpp b/platform/windows/mupdfwinrt/utils.cpp
new file mode 100644
index 00000000..9c20c620
--- /dev/null
+++ b/platform/windows/mupdfwinrt/utils.cpp
@@ -0,0 +1,28 @@
+#include "pch.h"
+#include "utils.h"
+
+/* Window string hurdles.... */
+String^ char_to_String(const char *char_in)
+{
+ size_t size = MultiByteToWideChar(CP_UTF8, 0, char_in, -1, NULL, 0);
+ wchar_t *pw;
+ pw = new wchar_t[size];
+ if (!pw)
+ {
+ delete []pw;
+ return nullptr;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, char_in, -1, pw, size );
+ String^ str_out = ref new String(pw);
+ delete []pw;
+ return str_out;
+}
+
+char* String_to_char(String^ text)
+{
+ const wchar_t *w = text->Data();
+ int cb = WideCharToMultiByte(CP_UTF8, 0, text->Data(), -1, nullptr, 0, nullptr, nullptr);
+ char* charout = new char[cb];
+ WideCharToMultiByte(CP_UTF8, 0, text->Data() ,-1 ,charout ,cb ,nullptr, nullptr);
+ return charout;
+}
diff --git a/platform/windows/mupdfwinrt/utils.h b/platform/windows/mupdfwinrt/utils.h
new file mode 100644
index 00000000..78f4dbc4
--- /dev/null
+++ b/platform/windows/mupdfwinrt/utils.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "Windows.h"
+using namespace Platform;
+
+String^ char_to_String(const char *char_in);
+char* String_to_char(String^ text);