2
0
mirror of https://github.com/koreader/koreader synced 2024-10-31 21:20:20 +00:00
koreader/cre.cpp
Dobrica Pavlinusic dadbf000c9 coolreader search highlight
This is rough port of Android code, but seems to work

Conflicts:

	cre.cpp
	crereader.lua
2012-09-17 12:58:43 -04:00

577 lines
15 KiB
C++

/*
KindlePDFViewer: CREngine abstraction for Lua
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
Qingping Hou <qingping.hou@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#define DEBUG_CRENGINE 1
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");
// should be save if called twice
if(doc->text_view != NULL) {
delete doc->text_view;
doc->text_view = NULL;
}
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()+1);
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 = 1;
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
page = doc->text_view->getBookmarkPage(xp) + 1;
lua_pushinteger(L, page);
return 1;
}
static int getPosFromXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *xpointer_str = luaL_checkstring(L, 2);
int pos = 0;
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
lvPoint pt = xp.toPoint();
if (pt.y > 0) {
pos = pt.y;
}
lua_pushinteger(L, pos);
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 getCurrentPercent(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getPosPercent());
return 1;
}
static int getCurrentXPointer(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;
}
static int getFontSize(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getFontSize());
return 1;
}
static int getFontFace(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushstring(L, doc->text_view->getDefaultFontFace().c_str());
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->getPage()+1);
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"
* },
* }
*
*/
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));
//fontMan->SetFallbackFontFace(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-1);
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.getText();
//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);
//printf("---------------- %s\n", UnicodeToLocal(sel.getSelectedWord()->getText()).c_str());
return 0;
}
static int drawCurrentView(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 2, "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;
}
// ported from Android UI kpvcrlib/crengine/android/jni/docview.cpp
static int findText(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *l_pattern = luaL_checkstring(L, 2);
lString16 pattern = lString16(l_pattern);
int origin = luaL_checkint(L, 3);
bool reverse = luaL_checkint(L, 4);
bool caseInsensitive = luaL_checkint(L, 5);
const char *l_lastPatt = luaL_checkstring(L, 6);
lString16 _lastPattern = lString16(l_lastPatt);
if ( pattern.empty() )
return 0;
if ( pattern!=_lastPattern && origin==1 )
origin = 0;
_lastPattern = pattern;
LVArray<ldomWord> words;
lvRect rc;
doc->text_view->GetPos( rc );
int pageHeight = rc.height();
int start = -1;
int end = -1;
if ( reverse ) {
// reverse
if ( origin == 0 ) {
// from end current page to first page
end = rc.bottom;
} else if ( origin == -1 ) {
// from last page to end of current page
start = rc.bottom;
} else { // origin == 1
// from prev page to first page
end = rc.top;
}
} else {
// forward
if ( origin == 0 ) {
// from current page to last page
start = rc.top;
} else if ( origin == -1 ) {
// from first page to current page
end = rc.top;
} else { // origin == 1
// from next page to last
start = rc.bottom;
}
}
CRLog::debug("CRViewDialog::findText: Current page: %d .. %d", rc.top, rc.bottom);
CRLog::debug("CRViewDialog::findText: searching for text '%s' from %d to %d origin %d", LCSTR(pattern), start, end, origin );
if ( doc->text_view->getDocument()->findText( pattern, caseInsensitive, reverse, start, end, words, 200, pageHeight ) ) {
CRLog::debug("CRViewDialog::findText: pattern found");
doc->text_view->clearSelection();
doc->text_view->selectWords( words );
ldomMarkedRangeList * ranges = doc->text_view->getMarkedRanges();
if ( ranges ) {
if ( ranges->length()>0 ) {
int pos = ranges->get(0)->start.y;
doc->text_view->SetPos(pos);
}
}
return 0;
}
CRLog::debug("CRViewDialog::findText: pattern not found");
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},
{"getPosFromXPointer", getPosFromXPointer},
{"getCurrentPos", getCurrentPos},
{"getCurrentPercent", getCurrentPercent},
{"getCurrentXPointer", getCurrentXPointer},
{"getFullHeight", getFullHeight},
{"getFontSize", getFontSize},
{"getFontFace", getFontFace},
{"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},
{"drawCurrentView", drawCurrentView},
{"findText", findText},
{"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;
}