diff options
author | Michael Vrhel <michael.vrhel@artifex.com> | 2014-09-09 16:31:31 -0700 |
---|---|---|
committer | Michael Vrhel <michael.vrhel@artifex.com> | 2014-09-09 16:39:41 -0700 |
commit | 7ea99e3a8951e265d1437a77dcfee069de0edf76 (patch) | |
tree | 8e113fea67931064e2a9338d67b26aaabab27512 /platform/windows/mupdfwinrt | |
parent | 8a9519f2183b64fe220bcb1f6acedbe6acc190cd (diff) | |
download | mupdf-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.cpp | 120 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/Cache.h | 38 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/ContentItem.cpp | 11 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/ContentItem.h | 58 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/Links.cpp | 12 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/Links.h | 88 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/muctx.cpp | 895 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/muctx.h | 123 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/mudocument.cpp | 470 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/mudocument.h | 55 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/mupdfwinrt.vcxproj | 249 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/mupdfwinrt.vcxproj.filters | 27 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/pch.cpp | 6 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/pch.h | 6 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/status.h | 19 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/utils.cpp | 28 | ||||
-rw-r--r-- | platform/windows/mupdfwinrt/utils.h | 7 |
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); |