/* KindlePDFViewer: CREngine abstraction for Lua Copyright (C) 2012 Hans-Werner Hilse Qingping Hou This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ extern "C" { #include "blitbuffer.h" #include "drawcontext.h" #include "cre.h" } #include "crengine.h" typedef struct CreDocument { LVDocView *text_view; ldomDocument *dom_doc; } CreDocument; static int openDocument(lua_State *L) { const char *file_name = luaL_checkstring(L, 1); const char *style_sheet = luaL_checkstring(L, 2); int width = luaL_checkint(L, 3); int height = luaL_checkint(L, 4); lString8 css; CreDocument *doc = (CreDocument*) lua_newuserdata(L, sizeof(CreDocument)); luaL_getmetatable(L, "credocument"); lua_setmetatable(L, -2); doc->text_view = new LVDocView(); //doc->text_view->setBackgroundColor(0xFFFFFF); //doc->text_view->setTextColor(0x000000); if (LVLoadStylesheetFile(lString16(style_sheet), css)){ if (!css.empty()){ doc->text_view->setStyleSheet(css); } } doc->text_view->setViewMode(DVM_SCROLL, -1); doc->text_view->Resize(width, height); doc->text_view->LoadDocument(file_name); doc->dom_doc = doc->text_view->getDocument(); doc->text_view->Render(); return 1; } static int getGammaIndex(lua_State *L) { lua_pushinteger(L, fontMan->GetGammaIndex()); return 1; } static int setGammaIndex(lua_State *L) { int index = luaL_checkint(L, 1); fontMan->SetGammaIndex(index); return 0; } static int closeDocument(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); delete doc->text_view; return 0; } static int getNumberOfPages(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); lua_pushinteger(L, doc->text_view->getPageCount()); return 1; } static int getCurrentPage(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); lua_pushinteger(L, doc->text_view->getCurPage()); return 1; } static int getPageFromXPointer(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); const char *xpointer_str = luaL_checkstring(L, 2); int page = 0; ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str)); page = doc->text_view->getBookmarkPage(xp); lua_pushinteger(L, page); return 1; } static int getCurrentPos(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); lua_pushinteger(L, doc->text_view->GetPos()); return 1; } //static int getPosFromXPointer(lua_State *L) { //CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); //const char *xpointer_str = luaL_checkstring(L, 2); //lvRect rc; //int pos; //ldomXPointer *xp = NULL; //xp = doc->dom_doc->createXPointer(lString16(xpointer_str)); //getCursorDocRect(*xp, rc); //pos = //return 1; //} static int getCurrentPercent(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); lua_pushinteger(L, doc->text_view->getPosPercent()); return 1; } static int getXPointer(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); ldomXPointer xp = doc->text_view->getBookmark(); lua_pushstring(L, UnicodeToLocal(xp.toString()).c_str()); return 1; } static int getFullHeight(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); lua_pushinteger(L, doc->text_view->GetFullHeight()); return 1; } /* * helper function for getTableOfContent() */ static int walkTableOfContent(lua_State *L, LVTocItem *toc, int *count) { LVTocItem *toc_tmp = NULL; int i = 0, nr_child = toc->getChildCount(); for(i = 0; i < nr_child; i++) { toc_tmp = toc->getChild(i); lua_pushnumber(L, (*count)++); /* set subtable, Toc entry */ lua_newtable(L); lua_pushstring(L, "page"); lua_pushnumber(L, toc_tmp->getPercent()); lua_settable(L, -3); lua_pushstring(L, "xpointer"); lua_pushstring(L, UnicodeToLocal( toc_tmp->getXPointer().toString()).c_str() ); lua_settable(L, -3); lua_pushstring(L, "depth"); lua_pushnumber(L, toc_tmp->getLevel()); lua_settable(L, -3); lua_pushstring(L, "title"); lua_pushstring(L, UnicodeToLocal(toc_tmp->getName()).c_str()); lua_settable(L, -3); /* set Toc entry to Toc table */ lua_settable(L, -3); if (toc_tmp->getChildCount() > 0) { walkTableOfContent(L, toc_tmp, count); } } return 0; } /* * Return a table like this: * { * { * page=12, * xpointer = "/body/DocFragment[11].0", * depth=1, * title="chapter1" * }, * { * page=54, * xpointer = "/body/DocFragment[13].0", * depth=1, * title="chapter2" * }, * } * * Warnning: not like pdf or djvu support, page here refers to the * percent of height within the document, not the real page number. * We use page here just to keep consistent with other readers. * */ static int getTableOfContent(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); LVTocItem * toc = doc->text_view->getToc(); int count = 0; lua_newtable(L); walkTableOfContent(L, toc, &count); return 1; } /* * Return a table like this: * { * "FreeMono", * "FreeSans", * "FreeSerif", * } * */ static int getFontFaces(lua_State *L) { int i = 0; lString16Collection face_list; fontMan->getFaceList(face_list); lua_newtable(L); for (i = 0; i < face_list.length(); i++) { lua_pushnumber(L, i+1); lua_pushstring(L, UnicodeToLocal(face_list[i]).c_str()); lua_settable(L, -3); } return 1; } static int setFontFace(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); const char *face = luaL_checkstring(L, 2); doc->text_view->setDefaultFontFace(lString8(face)); return 0; } static int gotoPage(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); int pageno = luaL_checkint(L, 2); doc->text_view->goToPage(pageno); return 0; } static int gotoPercent(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); int percent = luaL_checkint(L, 2); doc->text_view->SetPos(percent * doc->text_view->GetFullHeight() / 10000); return 0; } static int gotoPos(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); int pos = luaL_checkint(L, 2); doc->text_view->SetPos(pos); return 0; } static int gotoXPointer(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); const char *xpointer_str = luaL_checkstring(L, 2); ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str)); doc->text_view->goToBookmark(xp); /* CREngine does not call checkPos() immediately after goToBookmark, * so I have to manually update the pos in order to get a correct * return from GetPos() call. */ doc->text_view->SetPos(xp.toPoint().y); return 0; } /* zoom font by given delta and return zoomed font size */ static int zoomFont(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); int delta = luaL_checkint(L, 2); doc->text_view->ZoomFont(delta); lua_pushnumber(L, doc->text_view->getFontSize()); return 1; } static int setFontSize(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); int size = luaL_checkint(L, 2); doc->text_view->setFontSize(size); return 0; } static int setDefaultInterlineSpace(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); int space = luaL_checkint(L, 2); doc->text_view->setDefaultInterlineSpace(space); return 0; } static int setStyleSheet(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); const char* style_sheet_data = luaL_checkstring(L, 2); doc->text_view->setStyleSheet(lString8(style_sheet_data)); return 0; } static int toggleFontBolder(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); doc->text_view->doCommand(DCMD_TOGGLE_BOLD); return 0; } static int cursorRight(lua_State *L) { //CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); //LVDocView *tv = doc->text_view; //ldomXPointer p = tv->getCurrentPageMiddleParagraph(); //lString16 s = p.toString(); //printf("~~~~~~~~~~%s\n", UnicodeToLocal(s).c_str()); //tv->selectRange(*(tv->selectFirstPageLink())); //ldomXRange *r = tv->selectNextPageLink(true); //lString16 s = r->getRangeText(); //printf("------%s\n", UnicodeToLocal(s).c_str()); //tv->selectRange(*r); //tv->updateSelections(); //LVPageWordSelector sel(doc->text_view); //doc->text_view->doCommand(DCMD_SELECT_FIRST_SENTENCE); //sel.moveBy(DIR_RIGHT, 2); //sel.updateSelection(); //printf("---------------- %s\n", UnicodeToLocal(sel.getSelectedWord()->getText()).c_str()); return 0; } static int drawCurrentPage(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer"); int w = bb->w, h = bb->h; /* Set DrawBuf to 4bpp */ LVGrayDrawBuf drawBuf(w, h, 4); doc->text_view->Resize(w, h); doc->text_view->Render(); doc->text_view->Draw(drawBuf); uint8_t *bbptr = (uint8_t*)bb->data; uint8_t *pmptr = (uint8_t*)drawBuf.GetScanLine(0); int i,x; for (i = 0; i < h; i++) { for (x = 0; x < (bb->w / 2); x++) { /* When DrawBuf is set to 4bpp mode, CREngine still put every * four bits in one byte, but left the last 4 bits zero*/ bbptr[x] = ~(pmptr[x*2] | (pmptr[x*2+1] >> 4)); } if(bb->w & 1) { bbptr[x] = 255 - (pmptr[x*2] & 0xF0); } bbptr += bb->pitch; pmptr += w; } return 0; } static int registerFont(lua_State *L) { const char *fontfile = luaL_checkstring(L, 1); if ( !fontMan->RegisterFont(lString8(fontfile)) ) { return luaL_error(L, "cannot register font <%s>", fontfile); } return 0; } static const struct luaL_Reg cre_func[] = { {"openDocument", openDocument}, {"getFontFaces", getFontFaces}, {"getGammaIndex", getGammaIndex}, {"setGammaIndex", setGammaIndex}, {"registerFont", registerFont}, {NULL, NULL} }; static const struct luaL_Reg credocument_meth[] = { /*--- get methods ---*/ {"getPages", getNumberOfPages}, {"getCurrentPage", getCurrentPage}, {"getPageFromXPointer", getPageFromXPointer}, {"getCurrentPos", getCurrentPos}, {"getCurrentPercent", getCurrentPercent}, {"getXPointer", getXPointer}, {"getFullHeight", getFullHeight}, {"getToc", getTableOfContent}, /*--- set methods ---*/ {"setFontFace", setFontFace}, {"setFontSize", setFontSize}, {"setDefaultInterlineSpace", setDefaultInterlineSpace}, {"setStyleSheet", setStyleSheet}, /* --- control methods ---*/ {"gotoPage", gotoPage}, {"gotoPercent", gotoPercent}, {"gotoPos", gotoPos}, {"gotoXPointer", gotoXPointer}, {"zoomFont", zoomFont}, {"toggleFontBolder", toggleFontBolder}, //{"cursorLeft", cursorLeft}, //{"cursorRight", cursorRight}, {"drawCurrentPage", drawCurrentPage}, {"close", closeDocument}, {"__gc", closeDocument}, {NULL, NULL} }; int luaopen_cre(lua_State *L) { luaL_newmetatable(L, "credocument"); lua_pushstring(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); luaL_register(L, NULL, credocument_meth); lua_pop(L, 1); luaL_register(L, "cre", cre_func); /* initialize font manager for CREngine */ InitFontManager(lString8()); #ifdef DEBUG_CRENGINE CRLog::setStdoutLogger(); CRLog::setLogLevel(CRLog::LL_DEBUG); #endif return 1; }