summaryrefslogtreecommitdiff
path: root/winrt/mupdfwinrt
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2013-05-04 22:59:31 -0700
committerRobin Watts <robin.watts@artifex.com>2013-05-16 19:25:44 +0100
commitced8337a902cfb9988d014c099b90b2b66212825 (patch)
treec91a41d504b4cbddec169a2e5e4a2a5031863ad4 /winrt/mupdfwinrt
parent4bbdac7510e0a02f86fd00629a8b344d85404528 (diff)
downloadmupdf-ced8337a902cfb9988d014c099b90b2b66212825.tar.xz
Major changes in the entire design.
Initial commit of this and it has several issues that have to be worked through. Lots of broken stuff but I needed to get it in place. Added 2 new classes. One is muctx which contains all the interfacing to mupdf and uses standard c++ types. The other is mudocument which interfaces between muctx and the WinRT world. It passes WinRT objects to and from applications which can be written in C++, C#, Visual Basic, Javascript etc. mudocument and muctx will reside in a winRT DLL. The Viewer application (c++ version) is now in mupdf_cpp project and now has a flip view structure that includes a scroll viewer which has data binding to a collection. This enables much easier zooming and updating, however I am still trying how to bind the canvas elements that contain the text search or link information.
Diffstat (limited to 'winrt/mupdfwinrt')
-rw-r--r--winrt/mupdfwinrt/Links.cpp11
-rw-r--r--winrt/mupdfwinrt/Links.h72
-rw-r--r--winrt/mupdfwinrt/muctx.cpp404
-rw-r--r--winrt/mupdfwinrt/muctx.h81
-rw-r--r--winrt/mupdfwinrt/mudocument.cpp212
-rw-r--r--winrt/mupdfwinrt/mudocument.h40
-rw-r--r--winrt/mupdfwinrt/mupdfwinrt.vcxproj230
-rw-r--r--winrt/mupdfwinrt/mupdfwinrt.vcxproj.filters22
-rw-r--r--winrt/mupdfwinrt/pch.cpp6
-rw-r--r--winrt/mupdfwinrt/pch.h6
-rw-r--r--winrt/mupdfwinrt/utils.h8
11 files changed, 1092 insertions, 0 deletions
diff --git a/winrt/mupdfwinrt/Links.cpp b/winrt/mupdfwinrt/Links.cpp
new file mode 100644
index 00000000..eb8dfac7
--- /dev/null
+++ b/winrt/mupdfwinrt/Links.cpp
@@ -0,0 +1,11 @@
+#include "pch.h"
+#include "Links.h"
+
+using namespace mupdfwinrt;
+
+Links::Links(void)
+{
+ this->uri = nullptr;
+ this->page_num = -1;
+ this->type = NOT_SET;
+}
diff --git a/winrt/mupdfwinrt/Links.h b/winrt/mupdfwinrt/Links.h
new file mode 100644
index 00000000..64072e35
--- /dev/null
+++ b/winrt/mupdfwinrt/Links.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "utils.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/winrt/mupdfwinrt/muctx.cpp b/winrt/mupdfwinrt/muctx.cpp
new file mode 100644
index 00000000..fcdac960
--- /dev/null
+++ b/winrt/mupdfwinrt/muctx.cpp
@@ -0,0 +1,404 @@
+#pragma once
+
+#include "pch.h"
+#include "muctx.h"
+#include "Links.h"
+
+/* This class interfaces to mupdf API with minimal windows objects (other than
+ the file streaming stuff) */
+
+/* File streaming set up for mupdf */
+
+/* win_read_file etc. Reading of windows managed stream. This is not ideal as I have
+ to read into a managed buffer and then transfer to the actual buffer I want. I
+ would like a more direct approach. Alternate approach is to push this off
+ outside the winrt and read from a memory buffer. */
+static int win_read_file(fz_stream *stm, unsigned char *buf, int len)
+{
+ 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;
+ DataReader^ local_reader = ref new DataReader(Stream);
+ DataReaderLoadOperation^ result = local_reader->LoadAsync(len);
+
+ /* Block on the Async call */
+ while(result->Status != AsyncStatus::Completed) {
+
+ }
+
+ result->GetResults();
+ int curr_len2 = local_reader->UnconsumedBufferLength;
+ if (curr_len2 < len)
+ len = curr_len2;
+
+ Platform::Array<unsigned char>^ arrByte = ref new Platform::Array<unsigned char>(len);
+ local_reader->ReadBytes(arrByte);
+
+ memcpy(buf, arrByte->Data, len);
+ local_reader->DetachStream();
+
+ return len;
+}
+
+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->rp = stm->bp;
+ stm->wp = stm->bp;
+}
+
+static void win_close_file(fz_context *ctx, void *state)
+{
+ DataReader^ dataReader = reinterpret_cast <DataReader^> (state);
+
+ delete dataReader;
+}
+
+/* mutext functions see mupdf readme for details */
+static void lock_mutex(void *user, int lock)
+{
+ EnterCriticalSection((LPCRITICAL_SECTION)user);
+}
+
+static void unlock_mutex(void *user, int lock)
+{
+ LeaveCriticalSection((LPCRITICAL_SECTION)user);
+}
+
+/* Set up the context, mutex and cookie */
+HRESULT muctx::InitializeContext()
+{
+ /* Get the mutex set up */
+ InitializeCriticalSectionEx(&mu_criticalsec, 0, 0);
+ mu_locks.user = &mu_criticalsec;
+ 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_OUTOFMEMORY;
+ }
+ else
+ {
+ /* If we are fine, allocate the cookie for progress etc. */
+ this->mu_cookie = (fz_cookie*)malloc(sizeof(fz_cookie));
+ if (this->mu_cookie == NULL) {
+ fz_free_context(this->mu_ctx);
+ return E_OUTOFMEMORY;
+ }
+ else
+ return S_OK;
+ }
+}
+
+/* Initializer */
+muctx::muctx(void)
+{
+ this->mu_cookie = NULL;
+ this->mu_ctx = NULL;
+ this->mu_doc = NULL;
+ this->mu_outline = NULL;
+ this->mu_stream = NULL;
+}
+
+/* Destructor */
+muctx::~muctx(void)
+{
+ free(this->mu_cookie);
+ if (mu_outline != NULL)
+ fz_free_outline(mu_ctx, mu_outline);
+ if (mu_doc != NULL)
+ fz_close_document(mu_doc);
+ if (mu_ctx != NULL)
+ fz_free_context(mu_ctx);
+
+ this->mu_cookie = NULL;
+ this->mu_ctx = NULL;
+ this->mu_doc = NULL;
+ this->mu_outline = NULL;
+ this->mu_stream = NULL;
+}
+
+/* Set up the stream access */
+HRESULT muctx::InitializeStream(IRandomAccessStream^ readStream, char *ext)
+{
+ win_stream.stream = readStream;
+ this->mu_stream = fz_new_stream(mu_ctx, 0, win_read_file, win_close_file);
+ this->mu_stream->seek = win_seek_file;
+ this->mu_stream->state = reinterpret_cast <void*> (&win_stream);
+
+ /* Now lets see if we can open the file */
+ mu_doc = fz_open_document_with_stream(mu_ctx, ext, this->mu_stream);
+
+ if (mu_doc == NULL)
+ return E_FAIL;
+ else
+ return S_OK;
+}
+
+/* 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 */
+Point muctx::MeasurePage(int page_num)
+{
+ Point pageSize;
+ fz_rect rect;
+ fz_page *page;
+ fz_rect *bounds;
+
+ page = fz_load_page(mu_doc, page_num);
+ bounds = fz_bound_page(mu_doc, page, &rect);
+ pageSize.X = bounds->x1 - bounds->x0;
+ pageSize.Y = bounds->y1 - bounds->y0;
+
+ return pageSize;
+}
+
+/* Get page size */
+Point muctx::MeasurePage(fz_page *page)
+{
+ Point 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;
+}
+
+int muctx::GetTextSearch(int page_num, char* needle, sh_vector_text texts_vec)
+{
+ fz_page *page;
+ fz_text_sheet *sheet;
+ fz_device *dev;
+ fz_context *ctx_clone;
+ fz_text_page *text;
+ int k;
+ int hit_count = 0;
+
+ if (mu_cookie->abort == 1)
+ return hit_count;
+
+ ctx_clone = fz_clone_context(mu_ctx);
+
+ fz_var(page);
+ fz_var(sheet);
+ fz_var(dev);
+ fz_try(ctx_clone)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ sheet = fz_new_text_sheet(ctx_clone);
+ text = fz_new_text_page(ctx_clone, &fz_empty_rect);
+ dev = fz_new_text_device(ctx_clone, 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(ctx_clone, 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].x1;
+ texts_vec->push_back(text_search);
+ }
+ }
+ fz_always(ctx_clone)
+ {
+ if (page != NULL)
+ {
+ fz_free_page(mu_doc, page);
+ }
+ if (dev != NULL)
+ {
+ fz_free_device(dev);
+ }
+ if (sheet != NULL)
+ {
+ fz_free_text_sheet(ctx_clone, sheet);
+ }
+ }
+ fz_catch(ctx_clone)
+ {
+ return E_FAIL;
+ }
+ return hit_count;
+}
+
+
+
+/* Get the links and pack into a smart pointer structure */
+int muctx::GetLinks(int page_num, sh_vector_link links_vec)
+{
+ fz_page *page;
+ fz_link *links;
+ fz_context *ctx_clone;
+ int k = 0;
+ int num_links = 0;
+
+ if (mu_cookie->abort == 1)
+ return num_links;
+
+ ctx_clone = fz_clone_context(mu_ctx);
+
+ fz_var(page);
+ fz_var(links);
+ fz_try(ctx_clone)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ links = fz_load_links(mu_doc, page);
+
+ fz_link *curr_link = links;
+ if (curr_link == NULL)
+ return num_links;
+
+ /* 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.x1;
+
+ 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(ctx_clone)
+ {
+ if (page != NULL)
+ {
+ fz_free_page(mu_doc, page);
+ }
+ if (links != NULL)
+ {
+ fz_drop_link(ctx_clone, links);
+ }
+ }
+ fz_catch(ctx_clone)
+ {
+ return E_FAIL;
+ }
+ return num_links;
+}
+
+/* Render page_num to size width by height into bmp_data buffer */
+HRESULT muctx::RenderPage(int page_num, int width, int height,
+ unsigned char *bmp_data)
+{
+ fz_device *dev;
+ fz_pixmap *pix;
+ fz_page *page;
+ fz_matrix ctm, *pctm = &ctm;
+ Point page_size;
+ fz_context *ctx_clone;
+
+ if (mu_cookie->abort == 1)
+ return S_OK;
+
+ ctx_clone = fz_clone_context(mu_ctx);
+
+ fz_var(dev);
+ fz_var(pix);
+ fz_var(page);
+ fz_try(ctx_clone)
+ {
+ page = fz_load_page(mu_doc, page_num);
+ page_size = MeasurePage(page);
+
+ /* Figure out scale factors so that we get the desired size */
+ pctm = fz_scale(pctm, (float) width / page_size.X, (float) height / page_size.Y);
+ /* Flip on Y */
+ ctm.f = height;
+ ctm.d = -ctm.d;
+ pix = fz_new_pixmap_with_data(ctx_clone, fz_device_bgr, width, height, bmp_data);
+ fz_clear_pixmap_with_value(ctx_clone, pix, 255);
+ dev = fz_new_draw_device(ctx_clone, pix);
+ fz_run_page(mu_doc, page, dev, pctm, NULL);
+ }
+ fz_always(ctx_clone)
+ {
+ if (dev != NULL)
+ {
+ fz_free_device(dev);
+ }
+ if (pix != NULL)
+ {
+ fz_drop_pixmap(ctx_clone, pix);
+ }
+ if (page != NULL)
+ {
+ fz_free_page(mu_doc, page);
+ }
+ }
+ fz_catch(ctx_clone)
+ {
+ return E_FAIL;
+ }
+
+ fz_free_context(ctx_clone);
+
+ return S_OK;
+}
diff --git a/winrt/mupdfwinrt/muctx.h b/winrt/mupdfwinrt/muctx.h
new file mode 100644
index 00000000..61aec5a4
--- /dev/null
+++ b/winrt/mupdfwinrt/muctx.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <memory>
+#include <functional>
+#include <vector>
+#include "utils.h"
+
+#include <windows.h>
+#include <Winerror.h>
+#include <mutex>
+
+extern "C" {
+ #include "fitz.h"
+ #include "fitz-internal.h"
+ #include "muxps.h"
+ #include "mupdf.h"
+}
+
+#define MAX_SEARCH 500
+
+using namespace Windows::Foundation; /* For Point */
+
+typedef struct document_link_s
+{
+ link_t type;
+ Point upper_left;
+ Point 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>>
+
+typedef struct text_search_s
+{
+ Point upper_left;
+ Point 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>>
+
+/* Needed for file handling */
+using namespace Windows::Storage::Streams;
+using namespace Windows::Foundation;
+
+typedef struct win_stream_struct_s
+{
+ IRandomAccessStream^ stream;
+} win_stream_struct;
+
+class muctx
+{
+private:
+ CRITICAL_SECTION mu_criticalsec;
+ 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];
+ fz_cookie *mu_cookie;
+ fz_stream *mu_stream;
+
+public:
+ muctx(void);
+ ~muctx(void);
+ HRESULT InitializeStream(IRandomAccessStream^ readStream, char *ext);
+ int GetPageCount();
+ HRESULT InitializeContext();
+ HRESULT RenderPage(int page_num, int width, int height, unsigned char *bmp_data);
+ Point MeasurePage(int page_num);
+ Point MeasurePage(fz_page *page);
+ int GetLinks(int page_num, sh_vector_link links_vec);
+ int GetTextSearch(int page_num, char* needle, sh_vector_text texts_vec);
+};
+
+
+
+
diff --git a/winrt/mupdfwinrt/mudocument.cpp b/winrt/mupdfwinrt/mudocument.cpp
new file mode 100644
index 00000000..cf02083d
--- /dev/null
+++ b/winrt/mupdfwinrt/mudocument.cpp
@@ -0,0 +1,212 @@
+// mudocument.cpp
+#include "pch.h"
+#include "mudocument.h"
+
+using namespace mupdfwinrt;
+using namespace concurrency;
+using namespace Platform::Collections;
+
+/* Window string hurdles.... */
+static String^ char_to_String(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;
+}
+
+static 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;
+}
+
+mudocument::mudocument()
+{
+ this->mu_object.InitializeContext();
+ this->links = nullptr;
+}
+
+int mudocument::GetNumPages()
+{
+ return this->mu_object.GetPageCount();
+}
+
+Point mudocument::GetPageSize(int page_num)
+{
+ std::lock_guard<std::mutex> lock(mutex_lock);
+ return this->mu_object.MeasurePage(page_num);
+}
+
+Windows::Foundation::IAsyncAction^ mudocument::OpenFile(StorageFile^ file)
+{
+ return create_async([this, file]()
+ {
+ String^ path = file->Path;
+ const wchar_t *w = path->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)
+ {
+ HRESULT code = this->mu_object.InitializeStream(readStream, ext);
+ return;
+ }
+ else
+ {
+ delete readStream;
+ return;
+ }
+ }
+ catch(COMException^ ex) {
+ /* Need to do something useful here */
+ throw ex;
+ }
+ });
+ });
+}
+
+/* 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);
+}
+
+/* Pack the page into a bmp stream so that we can use it with an image brush */
+Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^
+ mudocument::RenderPage(int page_num, int width, int height)
+{
+ return create_async([this, width, height, page_num]() -> InMemoryRandomAccessStream^
+ {
+ /* Allocate space for bmp */
+ Array<unsigned char>^ bmp_data = ref new Array<unsigned char>(height * 4 * width);
+ /* Set up the memory stream */
+ InMemoryRandomAccessStream ^ras = ref new InMemoryRandomAccessStream();
+ DataWriter ^dw = ref new DataWriter(ras->GetOutputStreamAt(0));
+
+ /* Go ahead and write our header data into the memory stream */
+ Prepare_bmp(width, height, dw);
+
+ std::lock_guard<std::mutex> lock(mutex_lock);
+
+ /* Get raster bitmap stream */
+ HRESULT code = mu_object.RenderPage(page_num, width, height, &(bmp_data[0]));
+ if (code != S_OK)
+ {
+ throw ref new FailureException("Page Rendering Failed");
+ }
+ /* Now the data into the memory stream */
+ dw->WriteBytes(bmp_data);
+ DataWriterStoreOperation^ result = dw->StoreAsync();
+ /* Block on this Async call? */
+ while(result->Status != AsyncStatus::Completed) {
+ }
+ /* Return raster stream */
+ return ras;
+ });
+}
+
+int mudocument::ComputeLinks(int page_num)
+{
+ std::lock_guard<std::mutex> lock(mutex_lock);
+ /* 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>());
+ int num_items = mu_object.GetLinks(page_num, link_smart_ptr_vec);
+ if (num_items == 0)
+ return 0;
+ /* Pack into winRT type*/
+ this->links = ref new Platform::Collections::Vector<Links^>();
+ for (int k = 0; k < num_items; k++)
+ {
+ auto new_link = ref new Links();
+ sh_link muctx_link = link_smart_ptr_vec->at(k);
+ new_link->LowerRight = muctx_link->lower_right;
+ new_link->UpperLeft = muctx_link->upper_left;
+ 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);
+ }
+ this->links->Append(new_link);
+ }
+ return num_items;
+}
+
+Links^ mudocument::GetLink(int k)
+{
+ if (k >= this->links->Size)
+ return nullptr;
+ return this->links->GetAt(k);
+}
+
+int mudocument::ComputeTextSearch(String^ text, int page_num)
+{
+ std::lock_guard<std::mutex> lock(mutex_lock);
+ /* 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 = mu_object.GetTextSearch(page_num, text_char, text_smart_ptr_vec);
+ if (num_items == 0)
+ return 0;
+ /* Pack into winRT type*/
+ this->textsearch = ref new Platform::Collections::Vector<Links^>();
+ for (int k = 0; k < num_items; k++)
+ {
+ auto new_link = ref new Links();
+ sh_text muctx_text = text_smart_ptr_vec->at(k);
+ new_link->LowerRight = muctx_text->lower_right;
+ new_link->UpperLeft = muctx_text->upper_left;
+ new_link->Type = TEXTBOX;
+ this->textsearch->Append(new_link);
+ }
+ return num_items;
+}
+
diff --git a/winrt/mupdfwinrt/mudocument.h b/winrt/mupdfwinrt/mudocument.h
new file mode 100644
index 00000000..b315a18f
--- /dev/null
+++ b/winrt/mupdfwinrt/mudocument.h
@@ -0,0 +1,40 @@
+#pragma once
+
+/* This file contains the WinRT API interface between the muctx class which
+ implements the mupdf calls and the WinRT objects enabling calling from
+ C#, C++, Visual Basic, JavaScript applications */
+
+#include "muctx.h"
+#include "Links.h"
+#include "ppltasks.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;
+ public:
+ mudocument();
+ Windows::Foundation::IAsyncAction^ OpenFile(StorageFile^ file);
+ int GetNumPages();
+ Point GetPageSize(int page_num);
+ Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^
+ RenderPage(int page_num, int width, int height);
+ int ComputeLinks(int page_num);
+ Links^ GetLink(int k);
+ int ComputeTextSearch(String^ text, int page_num);
+
+ };
+} \ No newline at end of file
diff --git a/winrt/mupdfwinrt/mupdfwinrt.vcxproj b/winrt/mupdfwinrt/mupdfwinrt.vcxproj
new file mode 100644
index 00000000..5e8892be
--- /dev/null
+++ b/winrt/mupdfwinrt/mupdfwinrt.vcxproj
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.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>11.0</MinimumVisualStudioVersion>
+ <AppContainerApplication>true</AppContainerApplication>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110</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>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <GenerateManifest>false</GenerateManifest>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <GenerateManifest>false</GenerateManifest>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <GenerateManifest>false</GenerateManifest>
+ </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>../../xps/;../../pdf/;../../fitz/;%(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)</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>../../xps/;../../pdf/;../../fitz/;%(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)</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>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;%(AdditionalDependencies)</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>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;%(AdditionalDependencies)</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>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;%(AdditionalDependencies)</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>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <AdditionalDependencies>runtimeobject.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="Links.h" />
+ <ClInclude Include="muctx.h" />
+ <ClInclude Include="pch.h" />
+ <ClInclude Include="mudocument.h" />
+ <ClInclude Include="utils.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Links.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" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/winrt/mupdfwinrt/mupdfwinrt.vcxproj.filters b/winrt/mupdfwinrt/mupdfwinrt.vcxproj.filters
new file mode 100644
index 00000000..c00d9539
--- /dev/null
+++ b/winrt/mupdfwinrt/mupdfwinrt.vcxproj.filters
@@ -0,0 +1,22 @@
+<?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" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="pch.h" />
+ <ClInclude Include="mudocument.h" />
+ <ClInclude Include="muctx.h" />
+ <ClInclude Include="Links.h" />
+ <ClInclude Include="utils.h" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/winrt/mupdfwinrt/pch.cpp b/winrt/mupdfwinrt/pch.cpp
new file mode 100644
index 00000000..01484ff5
--- /dev/null
+++ b/winrt/mupdfwinrt/pch.cpp
@@ -0,0 +1,6 @@
+//
+// pch.cpp
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/winrt/mupdfwinrt/pch.h b/winrt/mupdfwinrt/pch.h
new file mode 100644
index 00000000..f815ac97
--- /dev/null
+++ b/winrt/mupdfwinrt/pch.h
@@ -0,0 +1,6 @@
+//
+// pch.h
+// Header for standard system include files.
+//
+
+#pragma once
diff --git a/winrt/mupdfwinrt/utils.h b/winrt/mupdfwinrt/utils.h
new file mode 100644
index 00000000..7485ee47
--- /dev/null
+++ b/winrt/mupdfwinrt/utils.h
@@ -0,0 +1,8 @@
+#pragma once
+
+typedef enum {
+ LINK_GOTO = 0,
+ LINK_URI,
+ TEXTBOX, /* Do double duty with this class */
+ NOT_SET,
+} link_t; \ No newline at end of file