diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | dillorc | 7 | ||||
-rw-r--r-- | dlib/dlib.c | 1 | ||||
-rw-r--r-- | doc/dillo.1 | 4 | ||||
-rw-r--r-- | doc/user_help.html | 11 | ||||
-rw-r--r-- | dpi/datauri.c | 5 | ||||
-rw-r--r-- | dpi/vsource.c | 4 | ||||
-rw-r--r-- | dw/Makefile.am | 1 | ||||
-rw-r--r-- | dw/fltkplatform.cc | 4 | ||||
-rw-r--r-- | dw/fltkui.cc | 8 | ||||
-rw-r--r-- | dw/fltkviewbase.cc | 5 | ||||
-rw-r--r-- | dw/hyphenator.cc | 365 | ||||
-rw-r--r-- | dw/hyphenator.hh | 88 | ||||
-rw-r--r-- | dw/table.hh | 20 | ||||
-rw-r--r-- | dw/textblock.cc | 190 | ||||
-rw-r--r-- | dw/textblock_iterator.cc | 219 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 2 | ||||
-rw-r--r-- | lout/misc.hh | 8 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/cache.c | 5 | ||||
-rw-r--r-- | src/capi.c | 58 | ||||
-rw-r--r-- | src/dillo.cc | 10 | ||||
-rw-r--r-- | src/domain.c | 151 | ||||
-rw-r--r-- | src/domain.h | 19 | ||||
-rw-r--r-- | src/html.cc | 24 | ||||
-rw-r--r-- | src/keys.cc | 1 | ||||
-rw-r--r-- | src/keys.hh | 1 | ||||
-rw-r--r-- | src/keysrc | 3 | ||||
-rw-r--r-- | src/paths.cc | 4 | ||||
-rw-r--r-- | src/paths.hh | 1 | ||||
-rw-r--r-- | src/png.c | 4 | ||||
-rw-r--r-- | src/prefs.c | 1 | ||||
-rw-r--r-- | src/prefs.h | 4 | ||||
-rw-r--r-- | src/prefsparser.cc | 11 | ||||
-rw-r--r-- | src/ui.cc | 9 | ||||
-rw-r--r-- | src/url.c | 16 | ||||
-rw-r--r-- | test/Makefile.am | 10 | ||||
-rw-r--r-- | test/trie.cc | 17 |
38 files changed, 900 insertions, 406 deletions
@@ -10,11 +10,22 @@ at http://hg.dillo.org/dillo dillo-3.0.3 [not released yet] +- Support for CSS display property - Patch: Johannes Hofmann + - Packed trie to optimize hyphenator memory consumption. + Patches: Johannes Hofmann +- Fix image input coordinates (BUG#1070) - When location bar is given focus, temporarily show panels if hidden (BUG#1093). + - Fix bug where data URI has charset but no media type. + - Bug meter line number fix for bare carriage returns. + - Add some more info to various bug meter messages. Patches: corvid ++- Automatic hyphenation. + Patch: Sebastian Geerken ++- Added the "view-source" keybinding (default: Ctrl-U). + Patch: Alexander Voigt ++- Introduced the domainrc mechanism for finer-grained control than + filter_auto_requests had provided. + Patch: p37sitdu, corvid ----------------------------------------------------------------------------- @@ -26,13 +26,6 @@ # (While browsing, this can be changed from the tools/settings menu.) #parse_embedded_css=YES -# How should Dillo restrict automatic requests (e.g., redirections, -# pages containing images or stylesheets)? -# allow_all -# same_domain : Permit www.example.org to load an image from img.example.org, -# but not from the unrelated ad.doubleclick.net. -#filter_auto_requests=same_domain - # Change the buffering scheme for drawing # 0 no double buffering - useful for debugging # 1 light buffering using a single back buffer for all windows diff --git a/dlib/dlib.c b/dlib/dlib.c index cdc7ca62..ebdaf0cd 100644 --- a/dlib/dlib.c +++ b/dlib/dlib.c @@ -909,7 +909,6 @@ char *dGethomedir () /* * Get a line from a FILE stream. - * It handles backslash as line-continues character. * Return value: read line on success, NULL on EOF. */ char *dGetline (FILE *stream) diff --git a/doc/dillo.1 b/doc/dillo.1 index 18c932a2..2efc6b4a 100644 --- a/doc/dillo.1 +++ b/doc/dillo.1 @@ -1,4 +1,4 @@ -.TH dillo 1 "June 12, 2012" "" "USER COMMANDS" +.TH dillo 1 "September 24, 2012" "" "USER COMMANDS" .SH NAME dillo \- web browser .SH SYNOPSIS @@ -36,7 +36,7 @@ Set initial window position where \fIGEO\fR is Display this help text and exit. .TP \fB\-l\fR, \fB\-\-local\fR -Don't load images for these URL(s). +Don't load images or stylesheets for these URL(s). .TP \fB\-v\fR, \fB\-\-version\fR Display version info and exit. diff --git a/doc/user_help.html b/doc/user_help.html index b8c3e580..d65170d9 100644 --- a/doc/user_help.html +++ b/doc/user_help.html @@ -14,7 +14,7 @@ <table width="100%" bgcolor="#8080f0" cellspacing="4" cellpadding="5" border="0o"> - <tr><td><big><font color="#302080">Welcome to Dillo 3.0</font></big> + <tr><td><big><font color="#302080">Welcome to Dillo 3</font></big> </table> <p> @@ -63,7 +63,7 @@ <tr><td BGCOLOR="#70a0c0"> <ul> <li> You can scroll around your Dillo main window using - CTRL+{PgUp|PgDwn|Home|End} or using the mouse middle button + {PgUp|PgDn|Home|End} or using the mouse middle button or mouse wheel. If nothing happens when keys are pressed, try <b> <font color="#5040a0">focusing</font></b> your Dillo main window first by clicking it (not on any link!:)). @@ -84,8 +84,8 @@ of the page currently viewed, but it will *not* reload embedded images during this process. - <li> Dialogs can be closed with the ESC key<br> - (ESC also hides the findbar and control panels). + <li> Dialogs can be closed with the ESC key. + (ESC also hides the findbar and control panels) <li> If you want to try a different control panel, right-click over the tools button and select one that suits your needs, then make @@ -136,7 +136,7 @@ the above rules apply for every word in it. </li> </ul> <p> - Dillo will scroll the page and highlight found text! + Dillo will scroll the page and highlight found text. <p> <small>Default shortcut: [CTRL]+"F".</small> @@ -302,6 +302,7 @@ <tr><td>Ctrl-T <td>Tab <td>New tab <tr><td>Ctrl-W <td>Window <td>quit tab/window <tr><td>Ctrl-O <td>Open <td>Open file +<tr><td>Ctrl-U <td>(conventional) <td>view source <tr><td>Ctrl-B <td>Bookmarks <td>view bookmarks <tr><td>Ctrl-Q <td>Quit <td>Quit dillo <tr><td>Back or "<b>,</b>" <td>< <td>previous page diff --git a/dpi/datauri.c b/dpi/datauri.c index f8e2ad94..055ecd9f 100644 --- a/dpi/datauri.c +++ b/dpi/datauri.c @@ -216,9 +216,6 @@ static void send_failure_message(const char *url, const char *mime_type, /* * Get mime type from the data URI. - * TODO: there's no point in handling "charset" because current dillo - * only handles ISO-LATIN-1. The FLTK2 version (utf-8) could use it in the - * future. */ static char *datauri_get_mime(char *url) { @@ -243,7 +240,7 @@ static char *datauri_get_mime(char *url) if (len == 0) { mime_type = dStrdup("text/plain;charset=US-ASCII"); } else if (!dStrnAsciiCasecmp(buf, "charset", 7)) { - mime_type = dStrconcat("text/plain", buf, NULL); + mime_type = dStrconcat("text/plain;", buf, NULL); } else { mime_type = dStrdup(buf); } diff --git a/dpi/vsource.c b/dpi/vsource.c index adf08a83..2f1129cb 100644 --- a/dpi/vsource.c +++ b/dpi/vsource.c @@ -78,9 +78,9 @@ void send_numbered_text(Dsh *sh, int data_size) while (*p) { snprintf(line_str, 32, "%2d: ", line); a_Dpip_dsh_write_str(sh, 0, line_str); - if ((p = strchr(q, '\n'))) { + if ((p = strpbrk(q, "\r\n"))) { a_Dpip_dsh_write(sh, 0, q, p - q + 1); - if (p[1] == '\r') + if (*p == '\r' && p[1] == '\n') ++p; ++line; } else { diff --git a/dw/Makefile.am b/dw/Makefile.am index 61c92b98..aa5c88c3 100644 --- a/dw/Makefile.am +++ b/dw/Makefile.am @@ -74,6 +74,7 @@ libDw_widgets_a_SOURCES = \ tablecell.cc \ tablecell.hh \ textblock.cc \ + textblock_iterator.cc \ textblock_linebreaking.cc \ textblock.hh diff --git a/dw/fltkplatform.cc b/dw/fltkplatform.cc index 099c449c..fecd76a7 100644 --- a/dw/fltkplatform.cc +++ b/dw/fltkplatform.cc @@ -123,8 +123,8 @@ FltkFont::FltkFont (core::style::FontAttrs *attrs) font = family->get (fa); fl_font(font, size); - /* WORKAROUND: fl_width(uint_t) is not working on non-xft X. - * Reported to FLTK as STR #2688 */ + // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in + // 1.3.0 (STR #2688). spaceWidth = misc::max(0, (int)fl_width(" ") + letterSpacing); int xx, xy, xw, xh; fl_text_extents("x", xx, xy, xw, xh); diff --git a/dw/fltkui.cc b/dw/fltkui.cc index f9e6f3f6..7d2f6cc5 100644 --- a/dw/fltkui.cc +++ b/dw/fltkui.cc @@ -568,8 +568,8 @@ void FltkEntryResource::sizeRequest (core::Requisition *requisition) if (displayed() && style) { FltkFont *font = (FltkFont*)style->font; fl_font(font->font,font->size); - /* WORKAROUND: fl_width(uint_t) is not working on non-xft X. - * Reported to FLTK as STR #2688 */ + // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in + // 1.3.0 (STR #2688). requisition->width = (int)fl_width ("n") * (maxLength == UNLIMITED_MAX_LENGTH ? 10 : maxLength) @@ -691,8 +691,8 @@ void FltkMultiLineTextResource::sizeRequest (core::Requisition *requisition) if (style) { FltkFont *font = (FltkFont*)style->font; fl_font(font->font,font->size); - /* WORKAROUND: fl_width(uint_t) is not working on non-xft X. - * Reported to FLTK as STR #2688 */ + // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in + // 1.3.0 (STR #2688). requisition->width = (int)fl_width ("n") * numCols + 2 * RELIEF_X_THICKNESS; requisition->ascent = diff --git a/dw/fltkviewbase.cc b/dw/fltkviewbase.cc index 240937e2..d9782a4e 100644 --- a/dw/fltkviewbase.cc +++ b/dw/fltkviewbase.cc @@ -472,8 +472,11 @@ void FltkViewBase::drawArc (core::style::Color *color, int y = translateCanvasYToViewY (centerY) - height / 2; fl_arc(x, y, width, height, angle1, angle2); - if (filled) + if (filled) { + // WORKAROUND: We call both fl_arc and fl_pie due to a FLTK bug + // (STR #2703) that was present in 1.3.0. fl_pie(x, y, width, height, angle1, angle2); + } } void FltkViewBase::drawPolygon (core::style::Color *color, diff --git a/dw/hyphenator.cc b/dw/hyphenator.cc index 97844538..62a47a73 100644 --- a/dw/hyphenator.cc +++ b/dw/hyphenator.cc @@ -2,9 +2,9 @@ #include "../lout/misc.hh" #include "../lout/unicode.hh" +#include <limits.h> #include <stdio.h> #include <string.h> -#include <limits.h> #define LEN 1000 @@ -25,26 +25,44 @@ HashTable <TypedPair <TypedPointer <core::Platform>, ConstString>, Hyphenator> (true, true); Hyphenator::Hyphenator (core::Platform *platform, - const char *patFile, const char *excFile) + const char *patFile, const char *excFile, int pack) { this->platform = platform; - tree = NULL; // As long we are not sure whether a pattern file can be read. + trie = NULL; // As long we are not sure whether a pattern file can be read. - FILE *patF = fopen (patFile, "r"); - if (patF) { - tree = new HashTable <Integer, Collection <Integer> > (true, true); - while (!feof (patF)) { - char buf[LEN + 1]; - char *s = fgets (buf, LEN, patF); - if (s) { - // TODO Better exit with an error, when the line is too long. - int l = strlen (s); - if (s[l - 1] == '\n') - s[l - 1] = 0; - insertPattern (s); + char buf[PATH_MAX + 1]; + snprintf(buf, sizeof (buf), "%s.trie", patFile); + FILE *trieF = fopen (buf, "r"); + + if (trieF) { + trie = new Trie (); + if (trie->load (trieF) != 0) { + delete trie; + trie = NULL; + } + fclose (trieF); + } + + if (trie == NULL) { + TrieBuilder trieBuilder(pack); + FILE *patF = fopen (patFile, "r"); + if (patF) { + + while (!feof (patF)) { + char buf[LEN + 1]; + char *s = fgets (buf, LEN, patF); + if (s) { + // TODO Better exit with an error, when the line is too long. + int l = strlen (s); + if (s[l - 1] == '\n') + s[l - 1] = 0; + insertPattern (&trieBuilder, s); + } } + + trie = trieBuilder.createTrie (); + fclose (patF); } - fclose (patF); } exceptions = NULL; // Again, only instantiated when needed. @@ -69,10 +87,8 @@ Hyphenator::Hyphenator (core::Platform *platform, Hyphenator::~Hyphenator () { - if (tree) - delete tree; - if (exceptions) - delete exceptions; + delete trie; + delete exceptions; } Hyphenator *Hyphenator::getHyphenator (core::Platform *platform, @@ -111,45 +127,38 @@ Hyphenator *Hyphenator::getHyphenator (core::Platform *platform, return hyphenator; } -void Hyphenator::insertPattern (char *s) +void Hyphenator::insertPattern (TrieBuilder *trieBuilder, char *s) { // Convert the a pattern like 'a1bc3d4' into a string of chars 'abcd' // and a list of points [ 0, 1, 0, 3, 4 ]. int l = strlen (s); char chars [l + 1]; - Vector <Integer> *points = new Vector <Integer> (1, true); + SimpleVector<char> points (1); // TODO numbers consisting of multiple digits? // TODO Encoding: This implementation works exactly like the Python // implementation, based on UTF-8. Does this always work? int numChars = 0; - for (int i = 0; s[i]; i++) - if (s[i] >= '0' && s[i] <= '9') - points->put (new Integer (s[i] - '0'), numChars); - else + for (int i = 0; s[i]; i++) { + if (s[i] >= '0' && s[i] <= '9') { + points.setSize(numChars + 1, '0'); + points.set(numChars, s[i]); + } else { chars[numChars++] = s[i]; + } + } chars[numChars] = 0; - for (int i = 0; i < numChars + 1; i++) { - Integer *val = points->get (i); - if (val == NULL) - points->put (new Integer (0), i); - } + points.setSize(numChars + 2, '0'); + points.set(numChars + 1, '\0'); // Insert the pattern into the tree. Each character finds a dict // another level down in the tree, and leaf nodes have the list of // points. - HashTable <Integer, Collection <Integer> > *t = tree; - for (int i = 0; chars[i]; i++) { - Integer c (chars[i]); - if (!t->contains(&c)) - t->put (new Integer (chars[i]), - new HashTable <Integer, Collection <Integer> > (true, true)); - t = (HashTable <Integer, Collection <Integer> >*) t->get (&c); - } + //printf("insertPattern %s\n", chars); - t->put (new Integer (0), points); + trieBuilder->insert (chars, points.getArray ()); } void Hyphenator::insertException (char *s) @@ -214,7 +223,7 @@ bool Hyphenator::isCharPartOfActualWord (char *s) */ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) { - if ((tree == NULL && exceptions ==NULL) || !isHyphenationCandidate (word)) { + if ((trie == NULL && exceptions ==NULL) || !isHyphenationCandidate (word)) { *numBreaks = 0; return NULL; } @@ -232,7 +241,7 @@ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) if (wordLc[startActualWord] == 0) { // No letters etc in word: do not hyphenate at all. - delete wordLc; + free (wordLc); *numBreaks = 0; return NULL; } @@ -254,14 +263,14 @@ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) int *result = new int[exceptionalBreaks->size()]; for (int i = 0; i < exceptionalBreaks->size(); i++) result[i] = exceptionalBreaks->get(i)->getValue() + startActualWord; - delete wordLc; + free (wordLc); *numBreaks = exceptionalBreaks->size(); return result; } - // tree == NULL means that there is no pattern file. - if (tree == NULL) { - delete wordLc; + // trie == NULL means that there is no pattern file. + if (trie == NULL) { + free (wordLc); *numBreaks = 0; return NULL; } @@ -275,25 +284,19 @@ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) SimpleVector <int> points (l + 1); points.setSize (l + 1, 0); - Integer null (0); - for (int i = 0; i < l; i++) { - HashTable <Integer, Collection <Integer> > *t = tree; - for (int j = i; j < l; j++) { - Integer c (work[j]); - if (t->contains (&c)) { - t = (HashTable <Integer, Collection <Integer> >*) t->get (&c); - if (t->contains (&null)) { - Vector <Integer> *p = (Vector <Integer>*) t->get (&null); - - for (int k = 0; k < p->size (); k++) - points.set(i + k, lout::misc::max (points.get (i + k), - p->get(k)->getValue())); - } - } else - break; + int state = trie->root; + + for (int j = i; j < l && trie->validState (state); j++) { + const char *p = trie->getData((unsigned char) work[j], &state); + + if (p) { + for (int k = 0; p[k]; k++) + points.set(i + k, + lout::misc::max (points.get (i + k), p[k] - '0')); + } } - } + } // No hyphens in the first two chars or the last two. // Characters are not bytes, so UTF-8 characters must be counted. @@ -317,19 +320,241 @@ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) } } - delete wordLc; + free (wordLc); *numBreaks = breakPos.size (); if (*numBreaks == 0) return NULL; else { - // Could save some cycles by directly returning the array in the - // SimpleVector. - int *breakPosArray = new int[*numBreaks]; - for (int i = 0; i < *numBreaks; i++) - breakPosArray[i] = breakPos.get(i); - return breakPosArray; + return breakPos.detachArray (); } } +Trie::TrieNode TrieBuilder::trieNodeNull = {'\0', 0, NULL}; + +TrieBuilder::TrieBuilder (int pack) +{ + this->pack = pack; + dataList = new SimpleVector <DataEntry> (10000); + stateStack = new SimpleVector <StackEntry> (10); + tree = new SimpleVector <Trie::TrieNode> (20000); + dataZone = new ZoneAllocator (1024); + stateStackPush(0); +} + +TrieBuilder::~TrieBuilder () +{ + delete dataList; + delete stateStack; + delete tree; + delete dataZone; +} + +void TrieBuilder::insert (const char *key, const char *value) +{ + dataList->increase (); + dataList->getLastRef ()->key = (unsigned char *) strdup(key); + dataList->getLastRef ()->value = dataZone->strdup (value); +} + +int TrieBuilder::keyCompare (const void *p1, const void *p2) +{ + DataEntry *pd1 = (DataEntry *) p1; + DataEntry *pd2 = (DataEntry *) p2; + + return strcmp ((char *) pd1->key, (char *) pd2->key); +} + +int TrieBuilder::insertState (StackEntry *state, bool root) +{ + int i, j; + + if (state->count == 0) + return 0; + + if (root) { + i = 0; // we reseve slot 0 for the root state + } else { + /* The bigger pack is the more slots we check and the smaller + * the trie will be, but CPU consumption also increases. + * Reasonable values for pack seemt to be between 256 and 1024. + */ + i = tree->size () - pack + 2 * state->count; + + if (i < 256) // reserve first 256 entries for the root state + i = 256; + } + + for (;; i++) { + if (i + 256 > tree->size ()) + tree->setSize (i + 256, trieNodeNull); + + for (j = 1; j < 256; j++) { + Trie::TrieNode *tn = tree->getRef(i + j); + + if (tn->c == j || ((state->next[j] || state->data[j]) && tn->c != 0)) + break; + } + + if (j == 256) // found a suitable slot + break; + } + + for (int j = 1; j < 256; j++) { + Trie::TrieNode *tn = tree->getRef(i + j); + + if (state->next[j] || state->data[j]) { + tn->c = j; + tn->next = state->next[j]; + tn->data = state->data[j]; + } + } + + assert (root || i >= 256); + assert (!root || i == 0); + return i; +} + +void TrieBuilder::stateStackPush (unsigned char c) +{ + stateStack->increase (); + StackEntry *e = stateStack->getLastRef (); + memset (e, 0, sizeof (StackEntry)); + e->c = c; +} + +int TrieBuilder::stateStackPop () +{ + int next = insertState (stateStack->getLastRef (), stateStack->size () == 1); + unsigned char c = stateStack->getLastRef ()->c; + const char *data = stateStack->getLastRef ()->data1; + + stateStack->setSize (stateStack->size () - 1); + + if (stateStack->size () > 0) { + assert (stateStack->getLastRef ()->next[c] == 0); + assert (stateStack->getLastRef ()->data[c] == NULL); + stateStack->getLastRef ()->next[c] = next; + stateStack->getLastRef ()->data[c] = data; + stateStack->getLastRef ()->count++; + } + + return next; +} + +Trie *TrieBuilder::createTrie () +{ + // we need to sort the patterns as byte strings not as unicode + qsort (dataList->getArray (), dataList->size (), + sizeof (DataEntry), keyCompare); + + for (int i = 0; i < dataList->size (); i++) { + insertSorted (dataList->getRef (i)->key, dataList->getRef (i)->value); + free (dataList->getRef (i)->key); + } + + while (stateStack->size ()) + stateStackPop (); + + int size = tree->size (); + Trie *trie = new Trie(tree->detachArray(), size, true, dataZone); + dataZone = NULL; + return trie; +} + +void TrieBuilder::insertSorted (unsigned char *s, const char *data) +{ + int len = strlen((char*)s); + + for (int i = 0; i < len; i++) { + if (stateStack->size () > i + 1 && + stateStack->getRef (i + 1)->c != s[i]) { + for (int j = stateStack->size () - 1; j >= i + 1; j--) + stateStackPop(); + } + + if (i + 1 >= stateStack->size ()) + stateStackPush(s[i]); + } + + while (stateStack->size () > len + 1) + stateStackPop(); + + assert (stateStack->size () == len + 1); + stateStack->getLastRef ()->data1 = data; +} + +Trie::Trie (TrieNode *array, int size, bool freeArray, ZoneAllocator *dataZone) +{ + this->array = array; + this->size = size; + this->freeArray = freeArray; + this->dataZone = dataZone; +}; + +Trie::~Trie () +{ + delete dataZone; + if (freeArray) + free(array); +}; + +void Trie::save (FILE *file) +{ + for (int i = 0; i < size; i++) { + Trie::TrieNode *tn = &array[i]; + + if (tn->data) + fprintf(file, "%u, %u, %s\n", tn->c, tn->next, tn->data); + else + fprintf(file, "%u, %u\n", tn->c, tn->next); + } +} + +int Trie::load (FILE *file) +{ + int next, c, maxNext = 0; + SimpleVector <TrieNode> tree (100); + dataZone = new ZoneAllocator (1024); + + while (!feof (file)) { + char buf[LEN + 1]; + char *s = fgets (buf, LEN, file); + + if (!s) + continue; + + char data[LEN + 1]; + int n = sscanf (s, "%u, %u, %s", &c, &next, data); + + if (n >= 2 && c >= 0 && c < 256 && next >= 0) { + tree.increase (); + tree.getLastRef ()->c = c; + tree.getLastRef ()->next = next; + if (n >= 3) + tree.getLastRef ()->data = dataZone->strdup (data); + else + tree.getLastRef ()->data = NULL; + + if (next > maxNext) + maxNext = next; + } else { + goto error; + } + } + + if (maxNext >= tree.size ()) + goto error; + + size = tree.size (); + array = tree.detachArray (); + freeArray = true; + return 0; + +error: + delete dataZone; + dataZone = NULL; + return 1; +} + } // namespace dw diff --git a/dw/hyphenator.hh b/dw/hyphenator.hh index 47530467..eadcf081 100644 --- a/dw/hyphenator.hh +++ b/dw/hyphenator.hh @@ -7,9 +7,84 @@ namespace dw { +class Trie { + public: + struct TrieNode { + unsigned char c; + uint16_t next; + const char *data; + }; + + private: + TrieNode *array; + int size; + bool freeArray; + lout::misc::ZoneAllocator *dataZone; + + public: + Trie (TrieNode *array = NULL, int size = 0, bool freeArray = false, + lout::misc::ZoneAllocator *dataZone = NULL); + ~Trie (); + + static const int root = 0; + inline bool validState (int state) { return state >= 0 && state < size; }; + inline const char *getData (unsigned char c, int *state) + { + if (!validState (*state)) + return NULL; + + TrieNode *tn = array + *state + c; + + if (tn->c == c) { + *state = tn->next > 0 ? tn->next : -1; + return tn->data; + } else { + *state = -1; + return NULL; + } + }; + void save (FILE *file); + int load (FILE *file); +}; + +class TrieBuilder { + private: + struct StackEntry { + unsigned char c; + int count; + int next[256]; + const char *data[256]; + const char *data1; + }; + + struct DataEntry { + unsigned char *key; + const char *value; + }; + + int pack; + static Trie::TrieNode trieNodeNull; + lout::misc::SimpleVector <Trie::TrieNode> *tree; + lout::misc::SimpleVector <DataEntry> *dataList; + lout::misc::SimpleVector <StackEntry> *stateStack; + lout::misc::ZoneAllocator *dataZone; + + static int keyCompare (const void *p1, const void *p2); + void stateStackPush (unsigned char c); + int stateStackPop (); + int insertState (StackEntry *state, bool root); + void insertSorted (unsigned char *key, const char *value); + + public: + TrieBuilder (int pack); + ~TrieBuilder (); + + void insert (const char *key, const char *value); + Trie *createTrie(); +}; + class Hyphenator: public lout::object::Object { -private: static lout::container::typed::HashTable <lout::object::TypedPair <lout::object::TypedPointer <core::Platform>, lout::object::ConstString>, @@ -21,26 +96,27 @@ private: * independent, but based on UTF-8. Clarify? Change? */ core::Platform *platform; - lout::container::typed::HashTable <lout::object::Integer, - lout::container::typed::Collection - <lout::object::Integer> > *tree; + Trie *trie; + lout::container::typed::HashTable <lout::object::ConstString, lout::container::typed::Vector <lout::object::Integer> > *exceptions; - void insertPattern (char *s); + + void insertPattern (TrieBuilder *trieBuilder, char *s); void insertException (char *s); bool isCharPartOfActualWord (char *s); public: Hyphenator (core::Platform *platform, - const char *patFile, const char *excFile); + const char *patFile, const char *excFile, int pack = 256); ~Hyphenator(); static Hyphenator *getHyphenator (core::Platform *platform, const char *language); static bool isHyphenationCandidate (const char *word); int *hyphenateWord(const char *word, int *numBreaks); + void saveTrie (FILE *fp) { trie->save (fp); }; }; } // namespace dw diff --git a/dw/table.hh b/dw/table.hh index 87bbaa76..7bcc6c1b 100644 --- a/dw/table.hh +++ b/dw/table.hh @@ -118,10 +118,8 @@ namespace dw { * * <ol> * <li> First, only cells with colspan = 1 are regarded: - * * \f[ e_{\hbox{base},i,\min} = \max \{ e_{\hbox{cell},i,j,\min} \} \f] * \f[ e_{\hbox{base},i,\max} = \max \{ e_{\hbox{cell},i,j,\max} \} \f] - * * only for cells \f$(i, j)\f$ with colspan = 1. * * <li> Then, @@ -130,29 +128,22 @@ namespace dw { * the cell at \f$(i_1, j)\f$ always span from \f$i_1\f$ to \f$i_2\f$.) * If the minimal width of the column exceeds the sum of the column minima * calculated in the last step: - * * \f[e_{\hbox{cell},i_1,j,\min} > * \sum_{i=i_1}^{i=i_2} e_{\hbox{base},i,\min}\f] - * * then the minimal width of this cell is apportioned to the columns: * * <ul> * <li> If the minimal width of this cell also exceeds the sum of the * column maxima: - * * \f[e_{\hbox{cell},i_1,j,\min} > * \sum_{i=i_1}^{i=i_2} e_{\hbox{base},i,\max}\f] - * * then \f$e_{\hbox{cell},i_1,j,\min}\f$ is apportioned in a simple * way: - * * \f[e_{\hbox{span},i,j,\min} = * e_{\hbox{base},i,\max} * {e_{\hbox{span},i,j,\min} \over * \sum_{i=i_1}^{i=i_2} e_{\hbox{base},i,\max}}\f] - * * <li> Otherwise, the apportionment function is used: - * * \f[e_{\hbox{span},i,j,\min} = * a_i (e_{\hbox{cell},i_1,j,\min}, * (e_{\hbox{cell},i_1,j,\min} \ldots @@ -172,6 +163,7 @@ namespace dw { * For the maxima, there is no \f$e_{\hbox{span},i,\max}\f$, but it has to * be assured, that the maximum is always greater than or equal to the * minimum. + * * </ol> * * Generally, if absolute widths are specified, they are, instead of the @@ -223,17 +215,13 @@ namespace dw { * no percentage width has been specified. The difference to the total * width is at max available to the columns with percentage width * specifications: - * * \f[W_{\hbox{columns}_\%,\hbox{available}} = W - \sum e_{i,\min}\f] - * * with only those columns \f$i\f$ with no percentage width specification. * * <li> Then, calculate the sum of the widths, which the columns with * percentage width specification would allocate, when fully adhering to * them: - * * \f[W_{\hbox{columns}_\%,\hbox{best}} = W \sum w_{i,\%}\f] - * * with only those columns \f$i\f$ with a percentage width specification. * * <li> Two cases are distinguished: @@ -243,25 +231,19 @@ namespace dw { * W_{\hbox{columns}_\%,\hbox{best}}\f$: In this case, the * percentage widths can be used without any modification, by * setting the extremes: - * * \f[e_{i,\min} = e_{i,\max} = W w_{i,\%}\f] - * * for only those columns \f$i\f$ with a percentage width * specification. * * <li> \f$W_{\hbox{columns}_\%,\hbox{available}} < * W_{\hbox{columns}_\%,\hbox{best}}\f$: In this case, the widths * for these columns must be cut down: - * * \f[e_{i,\min} = e_{i,\max} = * w_{i,\%} * {W_{\hbox{columns}_\%,\hbox{available}} \over * w_{\hbox{total},\%}}\f] - * * with - * * \f[w_{\hbox{total},\%} = \sum w_{i,\%}\f] - * * in both cases for only those columns \f$i\f$ with a percentage * width specification. * </ul> diff --git a/dw/textblock.cc b/dw/textblock.cc index 8c3134a6..ff94486b 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -2063,194 +2063,4 @@ core::Allocation *Textblock::getCBAllocation () return &allocation; } -// ---------------------------------------------------------------------- - -Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, - core::Content::Type mask, - bool atEnd): - core::Iterator (textblock, mask, atEnd) -{ - index = atEnd ? textblock->words->size () : -1; - content.type = atEnd ? core::Content::END : core::Content::START; -} - -Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, - core::Content::Type mask, - int index): - core::Iterator (textblock, mask, false) -{ - this->index = index; - - if (index < 0) - content.type = core::Content::START; - else if (index >= textblock->words->size ()) - content.type = core::Content::END; - else - content = textblock->words->getRef(index)->content; -} - -object::Object *Textblock::TextblockIterator::clone() -{ - return new TextblockIterator ((Textblock*)getWidget(), getMask(), index); -} - -int Textblock::TextblockIterator::compareTo(misc::Comparable *other) -{ - return index - ((TextblockIterator*)other)->index; -} - -bool Textblock::TextblockIterator::next () -{ - Textblock *textblock = (Textblock*)getWidget(); - - if (content.type == core::Content::END) - return false; - - do { - index++; - if (index >= textblock->words->size ()) { - content.type = core::Content::END; - return false; - } - } while ((textblock->words->getRef(index)->content.type & getMask()) == 0); - - content = textblock->words->getRef(index)->content; - return true; -} - -bool Textblock::TextblockIterator::prev () -{ - Textblock *textblock = (Textblock*)getWidget(); - - if (content.type == core::Content::START) - return false; - - do { - index--; - if (index < 0) { - content.type = core::Content::START; - return false; - } - } while ((textblock->words->getRef(index)->content.type & getMask()) == 0); - - content = textblock->words->getRef(index)->content; - return true; -} - -void Textblock::TextblockIterator::highlight (int start, int end, - core::HighlightLayer layer) -{ - Textblock *textblock = (Textblock*)getWidget(); - int index1 = index, index2 = index; - - if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index) { - /* nothing is highlighted */ - textblock->hlStart[layer].index = index; - textblock->hlEnd[layer].index = index; - } - - if (textblock->hlStart[layer].index >= index) { - index2 = textblock->hlStart[layer].index; - textblock->hlStart[layer].index = index; - textblock->hlStart[layer].nChar = start; - } - - if (textblock->hlEnd[layer].index <= index) { - index2 = textblock->hlEnd[layer].index; - textblock->hlEnd[layer].index = index; - textblock->hlEnd[layer].nChar = end; - } - - textblock->queueDrawRange (index1, index2); -} - -void Textblock::TextblockIterator::unhighlight (int direction, - core::HighlightLayer layer) -{ - Textblock *textblock = (Textblock*)getWidget(); - int index1 = index, index2 = index; - - if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index) - return; - - if (direction == 0) { - index1 = textblock->hlStart[layer].index; - index2 = textblock->hlEnd[layer].index; - textblock->hlStart[layer].index = 1; - textblock->hlEnd[layer].index = 0; - } else if (direction > 0 && textblock->hlStart[layer].index <= index) { - index1 = textblock->hlStart[layer].index; - textblock->hlStart[layer].index = index + 1; - textblock->hlStart[layer].nChar = 0; - } else if (direction < 0 && textblock->hlEnd[layer].index >= index) { - index1 = textblock->hlEnd[layer].index; - textblock->hlEnd[layer].index = index - 1; - textblock->hlEnd[layer].nChar = INT_MAX; - } - - textblock->queueDrawRange (index1, index2); -} - -void Textblock::queueDrawRange (int index1, int index2) -{ - int from = misc::min (index1, index2); - int to = misc::max (index1, index2); - - from = misc::min (from, words->size () - 1); - from = misc::max (from, 0); - to = misc::min (to, words->size () - 1); - to = misc::max (to, 0); - - int line1idx = findLineOfWord (from); - int line2idx = findLineOfWord (to); - - if (line1idx >= 0 && line2idx >= 0) { - Line *line1 = lines->getRef (line1idx), - *line2 = lines->getRef (line2idx); - int y = lineYOffsetWidget (line1) + line1->boxAscent - - line1->contentAscent; - int h = lineYOffsetWidget (line2) + line2->boxAscent + - line2->contentDescent - y; - - queueDrawArea (0, y, allocation.width, h); - } -} - -void Textblock::TextblockIterator::getAllocation (int start, int end, - core::Allocation *allocation) -{ - Textblock *textblock = (Textblock*)getWidget(); - int lineIndex = textblock->findLineOfWord (index); - Line *line = textblock->lines->getRef (lineIndex); - Word *word = textblock->words->getRef (index); - - allocation->x = - textblock->allocation.x + textblock->lineXOffsetWidget (line); - - for (int i = line->firstWord; i < index; i++) { - Word *w = textblock->words->getRef(i); - allocation->x += w->size.width + w->effSpace; - } - if (start > 0 && word->content.type == core::Content::TEXT) { - allocation->x += textblock->textWidth (word->content.text, 0, start, - word->style); - } - allocation->y = textblock->lineYOffsetCanvas (line) + line->boxAscent - - word->size.ascent; - - allocation->width = word->size.width; - if (word->content.type == core::Content::TEXT) { - int wordEnd = strlen(word->content.text); - - if (start > 0 || end < wordEnd) { - end = misc::min(end, wordEnd); /* end could be INT_MAX */ - allocation->width = - textblock->textWidth (word->content.text, start, end - start, - word->style); - } - } - allocation->ascent = word->size.ascent; - allocation->descent = word->size.descent; -} - } // namespace dw diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc new file mode 100644 index 00000000..63720ffb --- /dev/null +++ b/dw/textblock_iterator.cc @@ -0,0 +1,219 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * 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/>. + */ + +#include "textblock.hh" +#include "../lout/msg.h" +#include "../lout/misc.hh" + +#include <stdio.h> +#include <math.h> + +using namespace lout; + +namespace dw { + +Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, + core::Content::Type mask, + bool atEnd): + core::Iterator (textblock, mask, atEnd) +{ + index = atEnd ? textblock->words->size () : -1; + content.type = atEnd ? core::Content::END : core::Content::START; +} + +Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, + core::Content::Type mask, + int index): + core::Iterator (textblock, mask, false) +{ + this->index = index; + + if (index < 0) + content.type = core::Content::START; + else if (index >= textblock->words->size ()) + content.type = core::Content::END; + else + content = textblock->words->getRef(index)->content; +} + +object::Object *Textblock::TextblockIterator::clone() +{ + return new TextblockIterator ((Textblock*)getWidget(), getMask(), index); +} + +int Textblock::TextblockIterator::compareTo(misc::Comparable *other) +{ + return index - ((TextblockIterator*)other)->index; +} + +bool Textblock::TextblockIterator::next () +{ + Textblock *textblock = (Textblock*)getWidget(); + + if (content.type == core::Content::END) + return false; + + do { + index++; + if (index >= textblock->words->size ()) { + content.type = core::Content::END; + return false; + } + } while ((textblock->words->getRef(index)->content.type & getMask()) == 0); + + content = textblock->words->getRef(index)->content; + return true; +} + +bool Textblock::TextblockIterator::prev () +{ + Textblock *textblock = (Textblock*)getWidget(); + + if (content.type == core::Content::START) + return false; + + do { + index--; + if (index < 0) { + content.type = core::Content::START; + return false; + } + } while ((textblock->words->getRef(index)->content.type & getMask()) == 0); + + content = textblock->words->getRef(index)->content; + return true; +} + +void Textblock::TextblockIterator::highlight (int start, int end, + core::HighlightLayer layer) +{ + Textblock *textblock = (Textblock*)getWidget(); + int index1 = index, index2 = index; + + if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index) { + /* nothing is highlighted */ + textblock->hlStart[layer].index = index; + textblock->hlEnd[layer].index = index; + } + + if (textblock->hlStart[layer].index >= index) { + index2 = textblock->hlStart[layer].index; + textblock->hlStart[layer].index = index; + textblock->hlStart[layer].nChar = start; + } + + if (textblock->hlEnd[layer].index <= index) { + index2 = textblock->hlEnd[layer].index; + textblock->hlEnd[layer].index = index; + textblock->hlEnd[layer].nChar = end; + } + + textblock->queueDrawRange (index1, index2); +} + +void Textblock::TextblockIterator::unhighlight (int direction, + core::HighlightLayer layer) +{ + Textblock *textblock = (Textblock*)getWidget(); + int index1 = index, index2 = index; + + if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index) + return; + + if (direction == 0) { + index1 = textblock->hlStart[layer].index; + index2 = textblock->hlEnd[layer].index; + textblock->hlStart[layer].index = 1; + textblock->hlEnd[layer].index = 0; + } else if (direction > 0 && textblock->hlStart[layer].index <= index) { + index1 = textblock->hlStart[layer].index; + textblock->hlStart[layer].index = index + 1; + textblock->hlStart[layer].nChar = 0; + } else if (direction < 0 && textblock->hlEnd[layer].index >= index) { + index1 = textblock->hlEnd[layer].index; + textblock->hlEnd[layer].index = index - 1; + textblock->hlEnd[layer].nChar = INT_MAX; + } + + textblock->queueDrawRange (index1, index2); +} + +void Textblock::queueDrawRange (int index1, int index2) +{ + int from = misc::min (index1, index2); + int to = misc::max (index1, index2); + + from = misc::min (from, words->size () - 1); + from = misc::max (from, 0); + to = misc::min (to, words->size () - 1); + to = misc::max (to, 0); + + int line1idx = findLineOfWord (from); + int line2idx = findLineOfWord (to); + + if (line1idx >= 0 && line2idx >= 0) { + Line *line1 = lines->getRef (line1idx), + *line2 = lines->getRef (line2idx); + int y = lineYOffsetWidget (line1) + line1->boxAscent - + line1->contentAscent; + int h = lineYOffsetWidget (line2) + line2->boxAscent + + line2->contentDescent - y; + + queueDrawArea (0, y, allocation.width, h); + } +} + +void Textblock::TextblockIterator::getAllocation (int start, int end, + core::Allocation *allocation) +{ + Textblock *textblock = (Textblock*)getWidget(); + int lineIndex = textblock->findLineOfWord (index); + Line *line = textblock->lines->getRef (lineIndex); + Word *word = textblock->words->getRef (index); + + allocation->x = + textblock->allocation.x + textblock->lineXOffsetWidget (line); + + for (int i = line->firstWord; i < index; i++) { + Word *w = textblock->words->getRef(i); + allocation->x += w->size.width + w->effSpace; + } + if (start > 0 && word->content.type == core::Content::TEXT) { + allocation->x += textblock->textWidth (word->content.text, 0, start, + word->style); + } + allocation->y = textblock->lineYOffsetCanvas (line) + line->boxAscent - + word->size.ascent; + + allocation->width = word->size.width; + if (word->content.type == core::Content::TEXT) { + int wordEnd = strlen(word->content.text); + + if (start > 0 || end < wordEnd) { + end = misc::min(end, wordEnd); /* end could be INT_MAX */ + allocation->width = + textblock->textWidth (word->content.text, start, end - start, + word->style); + } + } + allocation->ascent = word->size.ascent; + allocation->descent = word->size.descent; +} + +} // namespace dw diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index f183ae0a..3835273d 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -712,7 +712,7 @@ int Textblock::hyphenateWord (int wordIndex) origWord.style->unref (); origWord.spaceStyle->unref (); - delete breakPos; + free (breakPos); } else { words->getRef(wordIndex)->canBeHyphenated = false; } diff --git a/lout/misc.hh b/lout/misc.hh index fe5cdcd5..437d229e 100644 --- a/lout/misc.hh +++ b/lout/misc.hh @@ -149,6 +149,14 @@ public: inline T* getArray() { return array; } + inline T* detachArray() { + T* arr = array; + array = NULL; + numAlloc = 0; + num = 0; + return arr; + } + /** * \brief Increase the vector size by one. * diff --git a/src/Makefile.am b/src/Makefile.am index 5e887d2c..05bbe00e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -82,6 +82,8 @@ dillo_SOURCES = \ dicache.h \ capi.c \ capi.h \ + domain.c \ + domain.h \ css.cc \ css.hh \ cssparser.cc \ diff --git a/src/cache.c b/src/cache.c index ea9d9a1f..4a689833 100644 --- a/src/cache.c +++ b/src/cache.c @@ -30,7 +30,7 @@ #include "capi.h" #include "decode.h" #include "auth.h" - +#include "domain.h" #include "timeout.hh" #include "uicmd.hh" @@ -682,8 +682,7 @@ static void Cache_parse_header(CacheEntry_t *entry) /* 30x: URL redirection */ DilloUrl *location_url = a_Url_new(location_str,URL_STR_(entry->Url)); - if (prefs.filter_auto_requests == PREFS_FILTER_SAME_DOMAIN && - !a_Url_same_organization(entry->Url, location_url)) { + if (!a_Domain_permit(entry->Url, location_url)) { /* don't redirect; just show body like usual (if any) */ MSG("Redirection not followed from %s to %s\n", URL_HOST(entry->Url), URL_STR(location_url)); @@ -26,6 +26,7 @@ #include "nav.h" #include "dpiapi.h" #include "uicmd.hh" +#include "domain.h" #include "../dpip/dpip.h" /* for testing dpi chat */ @@ -363,55 +364,6 @@ static void Capi_dpi_send_source(BrowserWindow *bw, DilloUrl *url) } /* - * When dillo wants to open an URL, this can be either due to user action - * (e.g., typing in an URL, clicking a link), or automatic (HTTP header - * indicates redirection, META HTML tag with refresh attribute and 0 delay, - * and images and stylesheets on an HTML page when autoloading is enabled). - * - * For a user request, the action will be permitted. - * For an automatic request, permission to load depends on the filter set - * by the user. - */ -static bool_t Capi_filters_test(const DilloUrl *wanted, - const DilloUrl *requester) -{ - bool_t ret; - - if (requester == NULL) { - /* request made by user */ - ret = TRUE; - } else { - switch (prefs.filter_auto_requests) { - case PREFS_FILTER_SAME_DOMAIN: - { - const char *req_host = URL_HOST(requester), - *want_host = URL_HOST(wanted); - if (want_host[0] == '\0') { - ret = (req_host[0] == '\0' || - !dStrAsciiCasecmp(URL_SCHEME(wanted), "data")) - ? TRUE : FALSE; - } else { - /* This will regard "www.dillo.org" and "www.dillo.org." as - * different, but it doesn't seem worth caring about. - */ - ret = a_Url_same_organization(wanted, requester); - } - if (ret == FALSE) { - MSG("Capi_filters_test: deny from '%s' to '%s'\n", req_host, - want_host); - } - break; - } - case PREFS_FILTER_ALLOW_ALL: - default: - ret = TRUE; - break; - } - } - return ret; -} - -/* * Most used function for requesting a URL. * TODO: clean up the ad-hoc bindings with an API that allows dynamic * addition of new plugins. @@ -427,8 +379,12 @@ int a_Capi_open_url(DilloWeb *web, CA_Callback_t Call, void *CbData) const char *scheme = URL_SCHEME(web->url); int safe = 0, ret = 0, use_cache = 0; - dReturn_val_if_fail((a_Capi_get_flags(web->url) & CAPI_IsCached) || - Capi_filters_test(web->url, web->requester), 0); + /* web->requester is NULL if the action is initiated by user */ + if (!(a_Capi_get_flags(web->url) & CAPI_IsCached || + web->requester == NULL || + a_Domain_permit(web->requester, web->url))) { + return 0; + } /* reload test */ reload = (!(a_Capi_get_flags(web->url) & CAPI_IsCached) || diff --git a/src/dillo.cc b/src/dillo.cc index 7552676d..3599ca7a 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -46,6 +46,7 @@ #include "capi.h" #include "dicache.h" #include "cookies.h" +#include "domain.h" #include "auth.h" #include "dw/fltkcore.hh" @@ -82,7 +83,8 @@ static const CLI_options Options[] = { {"-h", "--help", 0, DILLO_CLI_HELP, " -h, --help Display this help text and exit."}, {"-l", "--local", 0, DILLO_CLI_LOCAL, - " -l, --local Don't load images for these URL(s)."}, + " -l, --local Don't load images or stylesheets for these " + "URL(s)."}, {"-v", "--version", 0, DILLO_CLI_VERSION, " -v, --version Display version info and exit."}, {"-x", "--xid", 1, DILLO_CLI_XID, @@ -338,6 +340,11 @@ int main(int argc, char **argv) if ((fp = Paths::getPrefsFP(PATHS_RC_KEYS))) { Keys::parse(fp); } + // parse domainrc + if ((fp = Paths::getPrefsFP(PATHS_RC_DOMAIN))) { + a_Domain_parse(fp); + fclose(fp); + } dLib_show_messages(prefs.show_msg); // initialize internal modules @@ -441,6 +448,7 @@ int main(int argc, char **argv) * (This can be left to the OS, but we'll do it, with a view to test * and fix our memory management) */ + a_Domain_freeall(); a_Cookies_freeall(); a_Cache_freeall(); a_Dicache_freeall(); diff --git a/src/domain.c b/src/domain.c new file mode 100644 index 00000000..af8c8075 --- /dev/null +++ b/src/domain.c @@ -0,0 +1,151 @@ +/* + * File: domain.c + * + * 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. + */ + +#include <stdlib.h> + +#include "../dlib/dlib.h" +#include "msg.h" +#include "list.h" +#include "domain.h" + +typedef struct Rule { + char *origin; + char *destination; +} Rule; + +static Rule *exceptions = NULL; +static int num_exceptions = 0; +static int num_exceptions_max = 1; + +static bool_t default_deny = FALSE; + +/* + * Parse domainrc. + */ +void a_Domain_parse(FILE *fp) +{ + char *line; + uint_t lineno = 0; + + MSG("Reading domainrc...\n"); + + while ((line = dGetline(fp)) != NULL) { + ++lineno; + + /* Remove leading and trailing whitespace */ + dStrstrip(line); + + if (line[0] && line[0] != '#') { + const char *delim = " \t"; + char *tok1 = strtok(line, delim); + char *tok2 = strtok(NULL, delim); + + if (strtok(NULL, delim) != NULL) { + MSG("Domain: Ignoring extraneous text at end of line %u.\n", + lineno); + } + if (!tok2) { + MSG("Domain: Not enough fields in line %u.\n", lineno); + } else { + if (dStrAsciiCasecmp(tok1, "default") == 0) { + if (dStrAsciiCasecmp(tok2, "deny") == 0) { + default_deny = TRUE; + MSG("Domain: Default deny.\n"); + } else if (dStrAsciiCasecmp(tok2, "accept") == 0) { + default_deny = FALSE; + MSG("Domain: Default accept.\n"); + } else { + MSG("Domain: Default action \"%s\" not recognised.\n", tok2); + } + } else { + a_List_add(exceptions, num_exceptions, num_exceptions_max); + exceptions[num_exceptions].origin = dStrdup(tok1); + exceptions[num_exceptions].destination = dStrdup(tok2); + num_exceptions++; + MSG("Domain: Exception from %s to %s.\n", tok1, tok2); + } + } + } + dFree(line); + } +} + +void a_Domain_freeall(void) +{ + int i = 0; + + for (i = 0; i < num_exceptions; i++) { + dFree(exceptions[i].origin); + dFree(exceptions[i].destination); + } + dFree(exceptions); +} + +/* + * Wildcard ('*') pattern always matches. + * "example.org" pattern matches "example.org". + * ".example.org" pattern matches "example.org" and "sub.example.org". + */ +static bool_t Domain_match(const char *host, const char *pattern) { + int cmp = strcmp(pattern, "*"); + + if (cmp) { + if (pattern[0] != '.') + cmp = dStrAsciiCasecmp(host, pattern); + else { + int diff = strlen(host) - strlen(pattern); + + if (diff == -1) + cmp = dStrAsciiCasecmp(host, pattern + 1); + else if (diff >= 0) + cmp = dStrAsciiCasecmp(host + diff, pattern); + } + } + return cmp ? FALSE : TRUE; +} + +/* + * Is the resource at 'source' permitted to request the resource at 'dest'? + */ +bool_t a_Domain_permit(const DilloUrl *source, const DilloUrl *dest) +{ + int i; + bool_t ret; + const char *source_host, *dest_host; + + if (default_deny == FALSE && num_exceptions == 0) + return TRUE; + + source_host = URL_HOST(source); + dest_host = URL_HOST(dest); + + if (dest_host[0] == '\0') + return source_host[0] == '\0' || + !dStrAsciiCasecmp(URL_SCHEME(dest), "data"); + + if (a_Url_same_organization(source, dest)) + return TRUE; + + for (i = 0; i < num_exceptions; i++) { + if(Domain_match(source_host, exceptions[i].origin) && + Domain_match(dest_host, exceptions[i].destination)) { + ret = default_deny; + MSG("Domain: Matched rule from %s to %s.\n", exceptions[i].origin, + exceptions[i].destination); + break; + } + } + if (i == num_exceptions) + ret = default_deny ? FALSE : TRUE; + + MSG("Domain: %s from %s to %s.\n", + (ret == TRUE ? "permitted" : "DENIED"), source_host, dest_host); + + return ret; +} diff --git a/src/domain.h b/src/domain.h new file mode 100644 index 00000000..d1ca685b --- /dev/null +++ b/src/domain.h @@ -0,0 +1,19 @@ +#ifndef __DOMAIN_H__ +#define __DOMAIN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include "url.h" + +void a_Domain_parse(FILE *fp); +void a_Domain_freeall(void); +bool_t a_Domain_permit(const DilloUrl *source, const DilloUrl *dest); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/html.cc b/src/html.cc index c4a3d060..6f5e94ae 100644 --- a/src/html.cc +++ b/src/html.cc @@ -553,7 +553,7 @@ int DilloHtml::getCurTagLineNumber() ofs = CurrTagOfs; line = OldTagLine; for (i = OldTagOfs; i < ofs; ++i) - if (p[i] == '\n') + if (p[i] == '\n' || (p[i] == '\r' && p[i+1] != '\n')) ++line; OldTagOfs = CurrTagOfs; OldTagLine = line; @@ -934,7 +934,7 @@ static int Html_parse_entity(DilloHtml *html, const char *token, if (!isocode || errno || isocode > 0xffff) { /* this catches null bytes, errors and codes >= 0xFFFF */ - BUG_MSG("numeric character reference out of range\n"); + BUG_MSG("numeric character reference \"%s\" out of range\n", tok); isocode = -2; } @@ -3482,7 +3482,19 @@ static void Html_parse_common_attrs(DilloHtml *html, char *tag, int tagsize) html->styleEngine->setStyle (attrbuf); } - if (tagsize >= 10) { /* TODO prefs.hyphenate? */ + /* handle "xml:lang" and "lang" attributes */ + int hasXmlLang = 0; + if (tagsize >= 14) { + /* length of "<t xml:lang=i>" */ + attrbuf = Html_get_attr2(html, tag, tagsize, "xml:lang", + HTML_LeftTrim | HTML_RightTrim); + if (attrbuf) { + html->styleEngine->setNonCssHint(PROPERTY_X_LANG, CSS_TYPE_STRING, + attrbuf); + hasXmlLang = 1; + } + } + if (!hasXmlLang && tagsize >= 10) { /* 'xml:lang' prevails over 'lang' */ /* length of "<t lang=i>" */ attrbuf = Html_get_attr2(html, tag, tagsize, "lang", HTML_LeftTrim | HTML_RightTrim); @@ -3506,11 +3518,11 @@ static void Html_display_listitem(DilloHtml *html) ListItem *list_item; int *list_number; char buf[16]; - + /* Get our parent tag's variables (used as state storage) */ list_number = &html->stack->getRef(html->stack->size()-2)->list_number; ref_list_item = &html->stack->getRef(html->stack->size()-2)->ref_list_item; - + HT2TB(html)->addParbreak (0, wordStyle); list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width); @@ -3518,7 +3530,7 @@ static void Html_display_listitem(DilloHtml *html) HT2TB(html)->addParbreak (0, wordStyle); *ref_list_item = list_item; S_TOP(html)->textblock = html->dw = list_item; - + if (style->listStyleType == LIST_STYLE_TYPE_NONE) { // none } else if (style->listStyleType >= LIST_STYLE_TYPE_DECIMAL) { diff --git a/src/keys.cc b/src/keys.cc index 08d50306..27b275a3 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -122,6 +122,7 @@ static const KeyBinding_t default_keys[] = { { "forward" , KEYS_FORWARD , 0 , '.' }, { "goto" , KEYS_GOTO , FL_CTRL , 'l' }, { "home" , KEYS_HOME , FL_CTRL , 'h' }, + { "view-source" , KEYS_VIEW_SOURCE , FL_CTRL , 'u' }, { "screen-up" , KEYS_SCREEN_UP , 0 , FL_Page_Up }, { "screen-up" , KEYS_SCREEN_UP , 0 , 'b' }, { "screen-down" , KEYS_SCREEN_DOWN , 0 , FL_Page_Down }, diff --git a/src/keys.hh b/src/keys.hh index d3a5d586..8d2ec53c 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -37,6 +37,7 @@ typedef enum { KEYS_FORWARD, KEYS_GOTO, KEYS_HOME, + KEYS_VIEW_SOURCE, KEYS_SCREEN_UP, KEYS_SCREEN_DOWN, KEYS_SCREEN_LEFT, @@ -72,6 +72,9 @@ # "file-menu" pops up the file menu. #<alt>f = file-menu +# "view-source" displays the page source. +#<ctrl>u = view-source + # "goto" goes to the location bar at the top of the window. #<ctrl>l = goto diff --git a/src/paths.cc b/src/paths.cc index 6fccb89a..32478728 100644 --- a/src/paths.cc +++ b/src/paths.cc @@ -83,11 +83,11 @@ FILE *Paths::getPrefsFP(const char *rcFile) char *path = dStrconcat(dGethomedir(), "/.dillo/", rcFile, NULL); if (!(fp = fopen(path, "r"))) { - MSG("paths: Cannot open file '%s'\n", path); + MSG("paths: Cannot open file '%s': %s\n", path, dStrerror(errno)); char *path2 = dStrconcat(DILLO_SYSCONF, rcFile, NULL); if (!(fp = fopen(path2, "r"))) { - MSG("paths: Cannot open file '%s'\n",path2); + MSG("paths: Cannot open file '%s': %s\n", path2, dStrerror(errno)); MSG("paths: Using internal defaults...\n"); } else { MSG("paths: Using %s\n", path2); diff --git a/src/paths.hh b/src/paths.hh index a9efc62b..8f52cd86 100644 --- a/src/paths.hh +++ b/src/paths.hh @@ -14,6 +14,7 @@ #define PATHS_RC_PREFS "dillorc" #define PATHS_RC_KEYS "keysrc" +#define PATHS_RC_DOMAIN "domainrc" class Paths { public: @@ -64,7 +64,6 @@ struct _DilloPng { DilloUrl *url; /* Primary Key for the dicache */ int version; /* Secondary Key for the dicache */ - double display_exponent; /* gamma correction */ png_uint_32 width; /* png image width */ png_uint_32 height; /* png image height */ png_structp png_ptr; /* libpng private data */ @@ -75,7 +74,6 @@ struct _DilloPng { int error; /* error flag */ png_uint_32 previous_row; int rowbytes; /* No. bytes in image row */ - short passes; short channels; /* No. image channels */ /* @@ -177,7 +175,7 @@ Png_datainfo_callback(png_structp png_ptr, png_infop info_ptr) /* Interlaced */ if (interlace_type != PNG_INTERLACE_NONE) { - png->passes = png_set_interlace_handling(png_ptr); + png_set_interlace_handling(png_ptr); } /* get libpng to update its state */ diff --git a/src/prefs.c b/src/prefs.c index f243205a..a7fa1bcf 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -41,7 +41,6 @@ void a_Prefs_init(void) prefs.buffered_drawing = 1; prefs.contrast_visited_color = TRUE; prefs.enterpress_forces_submit = FALSE; - prefs.filter_auto_requests = PREFS_FILTER_SAME_DOMAIN; prefs.focus_new_tab = TRUE; prefs.font_cursive = dStrdup(PREFS_FONT_CURSIVE); prefs.font_factor = 1.0; diff --git a/src/prefs.h b/src/prefs.h index f1a3d538..7622aea3 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -26,9 +26,6 @@ extern "C" { /* Panel sizes */ enum { P_tiny = 0, P_small, P_medium }; -enum {PREFS_FILTER_ALLOW_ALL, - PREFS_FILTER_SAME_DOMAIN}; - typedef struct _DilloPrefs DilloPrefs; struct _DilloPrefs { @@ -77,7 +74,6 @@ struct _DilloPrefs { bool_t load_images; bool_t load_stylesheets; bool_t parse_embedded_css; - int filter_auto_requests; int32_t buffered_drawing; char *font_serif; char *font_sans_serif; diff --git a/src/prefsparser.cc b/src/prefsparser.cc index e74b5a6f..aa810b1e 100644 --- a/src/prefsparser.cc +++ b/src/prefsparser.cc @@ -29,7 +29,6 @@ typedef enum { PREFS_INT32, PREFS_DOUBLE, PREFS_GEOMETRY, - PREFS_FILTER, PREFS_PANEL_SIZE } PrefType_t; @@ -56,7 +55,6 @@ int PrefsParser::parseOption(char *name, char *value) { "contrast_visited_color", &prefs.contrast_visited_color, PREFS_BOOL }, { "enterpress_forces_submit", &prefs.enterpress_forces_submit, PREFS_BOOL }, - { "filter_auto_requests", &prefs.filter_auto_requests, PREFS_FILTER }, { "focus_new_tab", &prefs.focus_new_tab, PREFS_BOOL }, { "font_cursive", &prefs.font_cursive, PREFS_STRING }, { "font_factor", &prefs.font_factor, PREFS_DOUBLE }, @@ -166,15 +164,6 @@ int PrefsParser::parseOption(char *name, char *value) a_Misc_parse_geometry(value, &prefs.xpos, &prefs.ypos, &prefs.width, &prefs.height); break; - case PREFS_FILTER: - if (!dStrAsciiCasecmp(value, "same_domain")) - prefs.filter_auto_requests = PREFS_FILTER_SAME_DOMAIN; - else { - if (dStrAsciiCasecmp(value, "allow_all")) - MSG_WARN("prefs: unrecognized value for filter_auto_requests\n"); - prefs.filter_auto_requests = PREFS_FILTER_ALLOW_ALL; - } - break; case PREFS_PANEL_SIZE: if (!dStrAsciiCasecmp(value, "tiny")) prefs.panel_size = P_tiny; @@ -28,6 +28,8 @@ // Include image data #include "pixmaps.h" #include "uicmd.hh" +#include "history.h" +#include "nav.h" struct iconset { Fl_Image *ImgMeterOK, *ImgMeterBug, @@ -764,6 +766,11 @@ int UI::handle(int event) } else if (cmd == KEYS_FILE_MENU) { a_UIcmd_file_popup(a_UIcmd_get_bw_by_widget(this), FileButton); ret = 1; + } else if (cmd == KEYS_VIEW_SOURCE) { + BrowserWindow *bw = a_UIcmd_get_bw_by_widget(this); + const DilloUrl *url = a_History_get_url(NAV_TOP_UIDX(bw)); + a_UIcmd_view_page_source(bw, url); + ret = 1; } } else if (event == FL_RELEASE) { if (Fl::event_button() == FL_MIDDLE_MOUSE && @@ -815,7 +822,7 @@ void UI::set_location(const char *str) */ void UI::focus_location() { - if (Panelmode == UI_HIDDEN) { + if (Panelmode == UI_HIDDEN) { panels_toggle(); temporaryPanels(true); } @@ -688,15 +688,15 @@ static uint_t Url_host_public_internal_dots(const char *host) if (tld_len > 0) { /* These TLDs were chosen by examining the current publicsuffix list - * in September 2011 and picking out those where it was simplest for - * them to describe the situation by beginning with a "*.[tld]" rule. + * in October 2012 and picking out those where it was simplest for + * them to describe the situation by beginning with a "*.[tld]" rule + * or every rule was "[something].[tld]". */ - const char *const tlds[] = {"ar","au","bd","bn","bt","ck","cy", - "er","et","fj","fk","gt","gu","id", - "il","jm","ke","kh","kw","ml","mm","mt", - "mz","ni","np","nz","om","pg","py","qa", - "sv","tr","uk","uy","ve","ye","yu","za", - "zm","zw"}; + const char *const tlds[] = {"ar","au","bd","bn","ck","cy","er","et", + "fj","fk","gt","gu","il","jm","ke","kh", + "kp","kw","lb","lr","mm","mt","mz","ni", + "np","nz","om","pg","py","sv","tr","uk", + "ve","ye","za","zm","zw"}; uint_t i, tld_num = sizeof(tlds) / sizeof(tlds[0]); for (i = 0; i < tld_num; i++) { diff --git a/test/Makefile.am b/test/Makefile.am index bc851247..ab4c98b0 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,6 +24,7 @@ noinst_PROGRAMS = \ shapes \ cookies \ liang \ + trie \ notsosimplevector dw_anchors_test_SOURCES = dw_anchors_test.cc @@ -180,6 +181,15 @@ liang_LDADD = \ $(top_builddir)/lout/liblout.a \ @LIBFLTK_LIBS@ +trie_SOURCES = trie.cc + +trie_LDADD = \ + $(top_builddir)/dw/libDw-widgets.a \ + $(top_builddir)/dw/libDw-fltk.a \ + $(top_builddir)/dw/libDw-core.a \ + $(top_builddir)/lout/liblout.a \ + @LIBFLTK_LIBS@ + notsosimplevector_SOURCES = notsosimplevector.cc notsosimplevector_LDADD = $(top_builddir)/lout/liblout.a diff --git a/test/trie.cc b/test/trie.cc new file mode 100644 index 00000000..943b8045 --- /dev/null +++ b/test/trie.cc @@ -0,0 +1,17 @@ +#include "../dw/fltkcore.hh" +#include "../dw/hyphenator.hh" + +int main (int argc, char *argv[]) +{ + dw::fltk::FltkPlatform p; + + if (argc < 2) { + fprintf(stderr, "Usage: trie <pattern file>\n"); + exit (1); + } + + /* Use pack = 1024 to create a really small trie - can take a while. + */ + dw::Hyphenator hyphenator (&p, argv[1], NULL, 1024); + hyphenator.saveTrie (stdout); +} |