diff options
-rw-r--r-- | .hgignore | 1 | ||||
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | doc/dw-line-breaking.doc | 54 | ||||
-rw-r--r-- | dpi/downloads.cc | 14 | ||||
-rw-r--r-- | dpi/ftp.c | 14 | ||||
-rw-r--r-- | dpi/hello.c | 4 | ||||
-rw-r--r-- | dpi/https.c | 42 | ||||
-rw-r--r-- | dw/fltkcomplexbutton.cc | 27 | ||||
-rw-r--r-- | dw/fltkcomplexbutton.hh | 6 | ||||
-rw-r--r-- | dw/fltkui.cc | 16 | ||||
-rw-r--r-- | dw/hyphenator.cc | 56 | ||||
-rw-r--r-- | dw/hyphenator.hh | 21 | ||||
-rw-r--r-- | dw/textblock.cc | 134 | ||||
-rw-r--r-- | dw/textblock.hh | 8 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 65 | ||||
-rw-r--r-- | lout/unicode.cc | 105 | ||||
-rw-r--r-- | lout/unicode.hh | 8 | ||||
-rw-r--r-- | src/IO/dpi.c | 17 | ||||
-rw-r--r-- | src/auth.c | 13 | ||||
-rw-r--r-- | src/dialog.cc | 72 | ||||
-rw-r--r-- | src/dialog.hh | 19 | ||||
-rw-r--r-- | src/dillo.cc | 3 | ||||
-rw-r--r-- | src/dpiapi.c | 9 | ||||
-rw-r--r-- | src/form.cc | 10 | ||||
-rw-r--r-- | src/form.hh | 1 | ||||
-rw-r--r-- | src/html.cc | 2 | ||||
-rw-r--r-- | src/nav.c | 3 | ||||
-rw-r--r-- | src/plain.cc | 7 | ||||
-rw-r--r-- | src/tipwin.cc | 4 | ||||
-rw-r--r-- | src/uicmd.cc | 39 | ||||
-rw-r--r-- | test/Makefile.am | 13 | ||||
-rw-r--r-- | test/cookies.c | 15 | ||||
-rw-r--r-- | test/fltk_browser.cc | 43 | ||||
-rw-r--r-- | test/liang.cc | 4 | ||||
-rw-r--r-- | test/trie.cc | 5 | ||||
-rw-r--r-- | test/unicode_test.cc | 39 |
37 files changed, 537 insertions, 359 deletions
@@ -36,7 +36,6 @@ ^test/dw-table$ ^test/dw-table-aligned$ ^test/dw-ui-test$ -^test/fltk-browser$ ^test/liang$ ^test/notsosimplevector$ ^test/trie$ @@ -86,3 +86,4 @@ Non-Dillo code: public domain. * src/md5.[ch] contain code by L. Peter Deutsch whose copyright is held by Aladdin Enterprises. +* src/tipwin.cc contains code by Greg Ercolano. @@ -35,6 +35,8 @@ dillo-3.0.3 [not released yet] that character. - When active tab is closed, focus the previously visited one. Patches: Jorge Arellano Cid ++- Better window titles. + Patch: Jeremy Henty ----------------------------------------------------------------------------- diff --git a/doc/dw-line-breaking.doc b/doc/dw-line-breaking.doc index 8d9a1df1..54d03d19 100644 --- a/doc/dw-line-breaking.doc +++ b/doc/dw-line-breaking.doc @@ -327,30 +327,7 @@ None. Medium Priority --------------- -**Incorrect calculation of extremes:** The minimal width of a text -block (as part of the width extremes, which are mainly used for -tables) is defined by everything between two possible breaks. A -possible break may also be a hyphenation point; however, hyphenation -points are calculated in a lazy way, when the lines are broken, and -not when extremes are calculated. So, it is a matter of chance whether -the calculation of the minimal width will take the two parts "dil-" -and "lo" into account (when "dillo" has already been hyphenated), or -only one part, "dillo" (when "dillo" has not yet been hyphenated), -resulting possibly in a different value for the minimal width. - -Possible strategies to deal with this problem: - -- Ignore. The implications should be minimal. -- Any solution will make it neccessary to hyphenate at least some - words when calculating extremes. Since the minimal widths of all - words are used to calculate the minimal width of the text block, the - simplest approach will hyphenate all words. This would, of course, - eliminate the performance gains of the current lazy approach. -- The latter approach could be optimized in some ways. Examples: (i) - If a word is already narrower than the current accumulated value for - the minimal width, it makes no sense to hyphenate it. (ii) In other - cases, heuristics may be used to estimate the number of syllables, - the width of the widest of them etc. +None. Low Priority ------------ @@ -431,6 +408,35 @@ way, hyphens in adjacent lines are penalized further. **Solved:** There are always two penalties. Must be documented in detail. +*Incorrect calculation of extremes:* The minimal width of a text block +(as part of the width extremes, which are mainly used for tables) is +defined by everything between two possible breaks. A possible break +may also be a hyphenation point; however, hyphenation points are +calculated in a lazy way, when the lines are broken, and not when +extremes are calculated. So, it is a matter of chance whether the +calculation of the minimal width will take the two parts "dil-" and +"lo" into account (when "dillo" has already been hyphenated), or only +one part, "dillo" (when "dillo" has not yet been hyphenated), +resulting possibly in a different value for the minimal width. + +Possible strategies to deal with this problem: + +- Ignore. The implications should be minimal. +- Any solution will make it neccessary to hyphenate at least some + words when calculating extremes. Since the minimal widths of all + words are used to calculate the minimal width of the text block, the + simplest approach will hyphenate all words. This would, of course, + eliminate the performance gains of the current lazy approach. +- The latter approach could be optimized in some ways. Examples: (i) + If a word is already narrower than the current accumulated value for + the minimal width, it makes no sense to hyphenate it. (ii) In other + cases, heuristics may be used to estimate the number of syllables, + the width of the widest of them etc. + +**Solved:** Hyphenated parts of a word are not considered anymore for +width extremes, but only whole words. This is also one reason for the +introduction of the paragraphs list. + **Also:** - Configuration of penalties. diff --git a/dpi/downloads.cc b/dpi/downloads.cc index a25b511e..8e560d35 100644 --- a/dpi/downloads.cc +++ b/dpi/downloads.cc @@ -961,6 +961,7 @@ static void dlwin_esc_cb(Fl_Widget *, void *) "ABORT them and EXIT anyway?"; if (dl_win && dl_win->num_running() > 0) { + fl_message_title("Dillo Downloads: Abort downloads?"); int ch = fl_choice("%s", "Cancel", "*No", "Yes", msg); if (ch == 0 || ch == 1) return; @@ -1018,6 +1019,7 @@ DLAction DLWin::check_filename(char **p_fullname) dStr_sprintf(ds, "The file:\n %s (%d Bytes)\nalready exists. What do we do?", *p_fullname, (int)ss.st_size); + fl_message_title("Dillo Downloads: File exists!"); ch = fl_choice("%s", "Abort", "Continue", "Rename", ds->str); dStr_free(ds, 1); MSG("Choice %d\n", ch); @@ -1096,13 +1098,17 @@ class DlScroll : public Fl_Scroll public: void resize(int x_, int y_, int w_, int h_) { + Fl_Scroll::resize(x_, y_, w_, h_); Fl_Widget *resizable_ = resizable(); + int sb_size = + resizable_->h() <= h() ? 0 : + scrollbar_size() ? scrollbar_size() : + Fl::scrollbar_size(); if (resizable_) resizable_->resize(resizable_->x(), resizable_->y(), - w() - scrollbar_size(), + w() - sb_size, resizable_->h()); - Fl_Scroll::resize(x_, y_, w_, h_); } DlScroll(int x, int y, int w, int h, const char *l = 0) : Fl_Scroll(x, y, w, h, l) @@ -1119,7 +1125,7 @@ DLWin::DLWin(int ww, int wh) { mDList = new DLItemList(); // Create the empty main window - mWin = new Fl_Window(ww, wh, "Downloads:"); + mWin = new Fl_Window(ww, wh, "Dillo Downloads"); mWin->begin(); mScroll = new DlScroll(0,0,ww,wh); mScroll->begin(); @@ -1138,6 +1144,8 @@ DLWin::DLWin(int ww, int wh) { sigaddset(&mask_sigchld, SIGCHLD); est_sigchld(); + fl_message_title_default("Dillo Downloads: Message"); + // Set the cleanup timeout Fl::add_timeout(1.0, cleanup_cb, mDList); // Set the update timeout @@ -154,7 +154,7 @@ static void make_wget_argv(char *url) char *esc_url; if (dl_argv) { - dFree(dl_argv[2]); + dFree(dl_argv[3]); dFree(dl_argv); } dl_argv = dNew(char*, 10); @@ -164,9 +164,10 @@ static void make_wget_argv(char *url) Filter_smtp_hack(esc_url); dl_argv[0] = "wget"; - dl_argv[1] = "-O-"; - dl_argv[2] = esc_url; - dl_argv[3] = NULL; + dl_argv[1] = "-t1"; /* try once, default is 20 */ + dl_argv[2] = "-O-"; + dl_argv[3] = esc_url; + dl_argv[4] = NULL; } /* @@ -187,6 +188,8 @@ static int try_ftp_transfer(char *url) int aborted = 0; int DataPipe[2]; + MSG("try_ftp_transfer: url=%s\n", url); + if (pipe(DataPipe) < 0) { MSG("pipe, %s\n", dStrerror(errno)); return 0; @@ -316,7 +319,8 @@ int main(int argc, char **argv) if ((st = try_ftp_transfer(url)) == -1) { /* Transfer failed, the requested file may not exist or be a symlink * to a directory. Try again... */ - if ((p = strrchr(url, '/')) && p[1]) { + if ((p = strrchr(url, '/')) && p[1] && + p > url && p[-1] != '/') { url2 = dStrconcat(url, "/", NULL); st = try_ftp_transfer(url2); } diff --git a/dpi/hello.c b/dpi/hello.c index 4643efc5..d06c63ff 100644 --- a/dpi/hello.c +++ b/dpi/hello.c @@ -91,8 +91,8 @@ int main(void) /* Let's confirm the request */ /* NOTE: you can send less alternatives (e.g. only alt1 and alt2) */ d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s alt3=%s alt4=%s alt5=%s", - "dialog", "Do you want to see the hello page?", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s alt3=%s alt4=%s alt5=%s", + "dialog", "Dillo: Hello", "Do you want to see the hello page?", choice[1], choice[2], choice[3], choice[4], choice[5]); a_Dpip_dsh_write_str(sh, 1, d_cmd); dFree(d_cmd); diff --git a/dpi/https.c b/dpi/https.c index c2becdae..389c608d 100644 --- a/dpi/https.c +++ b/dpi/https.c @@ -434,8 +434,9 @@ static int handle_certificate_problem(SSL * ssl_connection) if (remote_cert == NULL){ /*Inform user that remote system cannot be trusted*/ d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: No certificate!", "The remote system is NOT presenting a certificate.\n" "This site CAN NOT be trusted. Sending data is NOT SAFE.\n" "What do I do?", @@ -477,8 +478,10 @@ static int handle_certificate_problem(SSL * ssl_connection) msg = dStrconcat("The remote certificate is self-signed and " "untrusted.\nFor address: ", buf, NULL); d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s alt3=%s", - "dialog", msg, "Continue", "Cancel", "Save Certificate"); + "cmd=%s title=%s msg=%s alt1=%s alt2=%s alt3=%s", + "dialog", + "Dillo HTTPS: Untrusted certificate!", msg, + "Continue", "Cancel", "Save Certificate"); a_Dpip_dsh_write_str(sh, 1, d_cmd); dFree(d_cmd); dFree(msg); @@ -504,8 +507,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Missing certificate issuer!", "The issuer for the remote certificate cannot be found\n" "The authenticity of the remote certificate cannot be trusted", "Continue", "Cancel"); @@ -523,8 +527,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_CRL_SIGNATURE_FAILURE: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Invalid certificate!", "The remote certificate signature could not be read\n" "or is invalid and should not be trusted", "Continue", "Cancel"); @@ -539,8 +544,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CRL_NOT_YET_VALID: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Certificate not yet valid!", "Part of the remote certificate is not yet valid\n" "Certificates usually have a range of dates over which\n" "they are to be considered valid, and the certificate\n" @@ -558,8 +564,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_HAS_EXPIRED: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Expired certificate!", "The remote certificate has expired. The certificate\n" "wasn't designed to last this long. You should avoid \n" "this site.", @@ -576,8 +583,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Certificate error!", "There was an error in the certificate presented.\n" "Some of the certificate data was improperly formatted\n" "making it impossible to determine if the certificate\n" @@ -596,8 +604,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_CERT_REJECTED: case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Certificate chain error!", "One of the certificates in the chain is being used\n" "incorrectly (possibly due to configuration problems\n" "with the remote system. The connection should not\n" @@ -614,8 +623,9 @@ static int handle_certificate_problem(SSL * ssl_connection) case X509_V_ERR_AKID_SKID_MISMATCH: case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Certificate mismatch!", "Some of the information presented by the remote system\n" "does not match other information presented\n" "This may be an attempt to eavesdrop on communications", @@ -629,8 +639,9 @@ static int handle_certificate_problem(SSL * ssl_connection) break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Self signed certificate!", "Self signed certificate in certificate chain. The certificate " "chain could be built up using the untrusted certificates but the " "root could not be found locally.", @@ -644,8 +655,9 @@ static int handle_certificate_problem(SSL * ssl_connection) break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", "dialog", + "Dillo HTTPS: Missing issuer certificate!", "Unable to get local issuer certificate. The issuer certificate " "of an untrusted certificate cannot be found.", "Continue", "Cancel"); @@ -660,8 +672,10 @@ static int handle_certificate_problem(SSL * ssl_connection) snprintf(buf, 80, "The remote certificate cannot be verified (code %ld)", st); d_cmd = a_Dpip_build_cmd( - "cmd=%s msg=%s alt1=%s alt2=%s", - "dialog", buf, "Continue", "Cancel"); + "cmd=%s title=%s msg=%s alt1=%s alt2=%s", + "dialog", + "Dillo HTTPS: Unverifiable certificate!", buf, + "Continue", "Cancel"); a_Dpip_dsh_write_str(sh, 1, d_cmd); dFree(d_cmd); response_number = dialog_get_answer_number(); diff --git a/dw/fltkcomplexbutton.cc b/dw/fltkcomplexbutton.cc index b866fb83..76af3713 100644 --- a/dw/fltkcomplexbutton.cc +++ b/dw/fltkcomplexbutton.cc @@ -45,7 +45,6 @@ int ComplexButton::value(int v) { void ComplexButton::draw() { Fl_Color col = value() ? selection_color() : color(); draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col); - if (Fl::focus() == this) draw_focus(); // ComplexButton is a Group; draw its children for (int i = children () - 1; i >= 0; i--) { @@ -53,6 +52,7 @@ void ComplexButton::draw() { child (i)->position(x()+(w()-child(i)->w())/2,y()+(h()-child(i)->h())/2); draw_child (*child (i)); } + if (Fl::focus() == this) draw_focus(); } int ComplexButton::handle(int event) { @@ -75,46 +75,37 @@ int ComplexButton::handle(int event) { value_ = newval; set_changed(); redraw(); - if (when() & FL_WHEN_CHANGED) do_callback(); } return 1; case FL_RELEASE: if (value_ == oldval) { - if (when() & FL_WHEN_NOT_CHANGED) do_callback(); return 1; } set_changed(); value(oldval); set_changed(); - if (when() & FL_WHEN_CHANGED) { - Fl_Widget_Tracker wp(this); - do_callback(); - if (wp.deleted()) return 1; - } if (when() & FL_WHEN_RELEASE) do_callback(); return 1; case FL_FOCUS : /* FALLTHROUGH */ case FL_UNFOCUS : if (Fl::visible_focus()) { - if (box() == FL_NO_BOX) { - // Widgets with the FL_NO_BOX boxtype need a parent to - // redraw, since it is responsible for redrawing the - // background... - int X = x() > 0 ? x() - 1 : 0; - int Y = y() > 0 ? y() - 1 : 0; - if (window()) window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2); - } else redraw(); + redraw(); return 1; } else return 0; case FL_KEYBOARD : if (Fl::focus() == this && (Fl::event_key() == ' ' || Fl::event_key() == FL_Enter) && !(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) { + value(1); set_changed(); - Fl_Widget_Tracker wp(this); - if (wp.deleted()) return 1; if (when() & FL_WHEN_RELEASE) do_callback(); return 1; + } else return 0; + case FL_KEYUP: + if (Fl::focus() == this && + (Fl::event_key() == ' ' || Fl::event_key() == FL_Enter)) { + value(0); + return 1; } default: return 0; diff --git a/dw/fltkcomplexbutton.hh b/dw/fltkcomplexbutton.hh index 43be6b57..6b3e73c1 100644 --- a/dw/fltkcomplexbutton.hh +++ b/dw/fltkcomplexbutton.hh @@ -23,15 +23,11 @@ #include <FL/Fl_Group.H> -extern FL_EXPORT Fl_Shortcut fl_old_shortcut(const char*); - namespace dw { namespace fltk { namespace ui { -class FL_EXPORT ComplexButton : public Fl_Group { - - int shortcut_; +class ComplexButton : public Fl_Group { char value_; char oldval; uchar down_box_; diff --git a/dw/fltkui.cc b/dw/fltkui.cc index 163080a6..4c3415c7 100644 --- a/dw/fltkui.cc +++ b/dw/fltkui.cc @@ -445,7 +445,7 @@ void FltkComplexButtonResource::widgetCallback (Fl_Widget *widget, { FltkComplexButtonResource *res = (FltkComplexButtonResource*)data; - if (!Fl::event_button3()) { + if (Fl::event() == FL_RELEASE && Fl::event_button() != FL_RIGHT_MOUSE) { int w = widget->w(), h = widget->h(); res->click_x = Fl::event_x() - widget->x(); @@ -462,6 +462,18 @@ void FltkComplexButtonResource::widgetCallback (Fl_Widget *widget, setButtonEvent(&event); res->emitClicked(&event); } + } else if (Fl::event() == FL_KEYBOARD) { + // Simulate a click. + dw::core::EventButton event; + + res->click_x = res->click_y = 0; + event.xCanvas = widget->x() + res->style->boxOffsetX(); + event.yCanvas = widget->y() + res->style->boxOffsetY(); + // ButtonState doesn't have mouse button values on a release. + event.state = (core::ButtonState) 0; + event.button = 1; + event.numPressed = 1; + res->emitClicked(&event); } } @@ -520,7 +532,7 @@ Fl_Widget *FltkComplexButtonResource::createNewWidget (core::Allocation button->callback (widgetCallback, this); button->when (FL_WHEN_RELEASE); if (!relief) - button->box(FL_FLAT_BOX); + button->box(FL_NO_BOX); flatView = new FltkFlatView (allocation->x + reliefXThickness (), allocation->y + reliefYThickness (), diff --git a/dw/hyphenator.cc b/dw/hyphenator.cc index cec5a9d8..c2b9755e 100644 --- a/dw/hyphenator.cc +++ b/dw/hyphenator.cc @@ -9,25 +9,23 @@ #define LEN 1000 /* - * This is a direct translation of the Python implementation by Ned - * Batchelder. + * This is (or at least began as) a direct translation of Ned Batchelder's + * public-domain Python implementation at + * http://nedbatchelder.com/code/modules/hyphenate.py */ using namespace lout::object; using namespace lout::container::typed; using namespace lout::misc; +using namespace lout::unicode; namespace dw { -HashTable <TypedPair <TypedPointer <core::Platform>, ConstString>, - Hyphenator> *Hyphenator::hyphenators = - new HashTable <TypedPair <TypedPointer <core::Platform>, ConstString>, - Hyphenator> (true, true); +HashTable <String, Hyphenator> *Hyphenator::hyphenators = + new HashTable <String, Hyphenator> (true, true); -Hyphenator::Hyphenator (core::Platform *platform, - const char *patFile, const char *excFile, int pack) +Hyphenator::Hyphenator (const char *patFile, const char *excFile, int pack) { - this->platform = platform; trie = NULL; // As long we are not sure whether a pattern file can be read. char buf[PATH_MAX + 1]; @@ -91,20 +89,13 @@ Hyphenator::~Hyphenator () delete exceptions; } -Hyphenator *Hyphenator::getHyphenator (core::Platform *platform, - const char *lang) +Hyphenator *Hyphenator::getHyphenator (const char *lang) { - // TODO Not very efficient. Other key than TypedPair? - // (Keeping the parts of the pair on the stack does not help, since - // ~TypedPair deletes them, so they have to be kept on the heap.) - TypedPair <TypedPointer <core::Platform>, ConstString> *pair = - new TypedPair <TypedPointer <core::Platform>, - ConstString> (new TypedPointer <core::Platform> (platform), - new String (lang)); - - Hyphenator *hyphenator = hyphenators->get (pair); + String *langString = new String (lang); + + Hyphenator *hyphenator = hyphenators->get (langString); if (hyphenator) - delete pair; + delete langString; else { char patFile [PATH_MAX]; snprintf (patFile, sizeof (patFile), "%s/hyphenation/%s.pat", @@ -116,8 +107,8 @@ Hyphenator *Hyphenator::getHyphenator (core::Platform *platform, //printf ("Loading hyphenation patterns for language '%s' from '%s' and " // "exceptions from '%s' ...\n", lang, patFile, excFile); - hyphenator = new Hyphenator (platform, patFile, excFile); - hyphenators->put (pair, hyphenator); + hyphenator = new Hyphenator (patFile, excFile); + hyphenators->put (langString, hyphenator); } //lout::misc::StringBuffer sb; @@ -215,13 +206,14 @@ bool Hyphenator::isCharPartOfActualWord (char *s) (unsigned char)s[1] == 0x9f /* ß */ )); #endif - return lout::unicode::isAlpha (lout::unicode::decodeUtf8 (s)); + return isAlpha (decodeUtf8 (s)); } /** * Given a word, returns a list of the possible hyphenation points. */ -int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) +int *Hyphenator::hyphenateWord(core::Platform *platform, + const char *word, int *numBreaks) { if ((trie == NULL && exceptions ==NULL) || !isHyphenationCandidate (word)) { *numBreaks = 0; @@ -261,7 +253,7 @@ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) } else nextStart = end; - hyphenateSingleWord (wordLc + start, start, &breakPos); + hyphenateSingleWord (platform, wordLc + start, start, &breakPos); start = nextStart; } @@ -279,8 +271,9 @@ int *Hyphenator::hyphenateWord(const char *word, int *numBreaks) * Hyphenate a single word, which only consists of lowercase * characters. Store break positions + "offset" in "breakPos". */ -void Hyphenator::hyphenateSingleWord(char *wordLc, int offset, - SimpleVector <int> *breakPos) +void Hyphenator::hyphenateSingleWord(core::Platform *platform, + char *wordLc, int offset, + SimpleVector <int> *breakPos) { // If the word is an exception, get the stored points. Vector <Integer> *exceptionalBreaks; @@ -324,9 +317,10 @@ void Hyphenator::hyphenateSingleWord(char *wordLc, int offset, // No hyphens in the first two chars or the last two. // Characters are not bytes, so UTF-8 characters must be counted. - int numBytes1Start = platform->nextGlyph (wordLc, 0); - int numBytes2Start = platform->nextGlyph (wordLc, numBytes1Start); - for (int i = 0; i < numBytes2Start; i++) + const char *bytesStart = nextUtf8Char (nextUtf8Char (wordLc)); + // TODO Check bytesStart == NULL; + int numBytesStart = bytesStart - wordLc; + for (int i = 0; i < numBytesStart; i++) points.set (i + 1, 0); int len = strlen (wordLc); diff --git a/dw/hyphenator.hh b/dw/hyphenator.hh index b02265ec..7716b857 100644 --- a/dw/hyphenator.hh +++ b/dw/hyphenator.hh @@ -86,16 +86,7 @@ class TrieBuilder { class Hyphenator: public lout::object::Object { static lout::container::typed::HashTable - <lout::object::TypedPair <lout::object::TypedPointer <core::Platform>, - lout::object::ConstString>, - Hyphenator> *hyphenators; - - /* - * Actually, only one method in Platform is needed: - * textToLower(). And, IMO, this method is actually not platform - * independent, but based on UTF-8. Clarify? Change? - */ - core::Platform *platform; + <lout::object::String, Hyphenator> *hyphenators; Trie *trie; lout::container::typed::HashTable <lout::object::ConstString, @@ -105,19 +96,17 @@ class Hyphenator: public lout::object::Object void insertPattern (TrieBuilder *trieBuilder, char *s); void insertException (char *s); - void hyphenateSingleWord(char *wordLc, int offset, + void hyphenateSingleWord(core::Platform *platform, char *wordLc, int offset, lout::misc::SimpleVector <int> *breakPos); bool isCharPartOfActualWord (char *s); public: - Hyphenator (core::Platform *platform, - const char *patFile, const char *excFile, int pack = 256); + Hyphenator (const char *patFile, const char *excFile, int pack = 256); ~Hyphenator(); - static Hyphenator *getHyphenator (core::Platform *platform, - const char *language); + static Hyphenator *getHyphenator (const char *language); static bool isHyphenationCandidate (const char *word); - int *hyphenateWord(const char *word, int *numBreaks); + int *hyphenateWord(core::Platform *platform, const char *word, int *numBreaks); void saveTrie (FILE *fp) { trie->save (fp); }; }; diff --git a/dw/textblock.cc b/dw/textblock.cc index 745e8ba8..96f33e92 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -21,6 +21,7 @@ #include "textblock.hh" #include "../lout/msg.h" #include "../lout/misc.hh" +#include "../lout/unicode.hh" #include <stdio.h> #include <math.h> // remove again? @@ -35,6 +36,7 @@ static dw::core::style::Tooltip *hoverTooltip = NULL; using namespace lout; +using namespace lout::unicode; namespace dw { @@ -316,7 +318,7 @@ void Textblock::getWordExtremes (Word *word, core::Extremes *extremes) void Textblock::getExtremesImpl (core::Extremes *extremes) { - PRINTF ("[%p] GET_EXTREMES: ...\n", this); + PRINTF ("[%p] GET_EXTREMES ...\n", this); fillParagraphs (); @@ -334,7 +336,8 @@ void Textblock::getExtremesImpl (core::Extremes *extremes) extremes->minWidth += diff; extremes->maxWidth += diff; - PRINTF ("=> %d / %d\n", extremes->minWidth, extremes->maxWidth); + PRINTF ("[%p] GET_EXTREMES => %d / %d\n", + this, extremes->minWidth, extremes->maxWidth); } @@ -1340,6 +1343,32 @@ int Textblock::findLineOfWord (int wordIndex) } /** + * \brief Find the paragraph of word \em wordIndex. + */ +int Textblock::findParagraphOfWord (int wordIndex) +{ + int high = paragraphs->size () - 1, index, low = 0; + + if (wordIndex < 0 || wordIndex >= words->size () || + // It may be that the paragraphs list is incomplete. But look + // also at fillParagraphs, where this method is called. + (paragraphs->size () > 0 && + wordIndex > paragraphs->getLastRef()->lastWord)) + return -1; + + while (true) { + index = (low + high) / 2; + if (wordIndex >= paragraphs->getRef(index)->firstWord) { + if (wordIndex <= paragraphs->getRef(index)->lastWord) + return index; + else + low = index + 1; + } else + high = index - 1; + } +} + +/** * \brief Find the index of the word, or -1. */ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace) @@ -1413,17 +1442,16 @@ void Textblock::draw (core::View *view, core::Rectangle *area) * Add a new word (text, widget etc.) to a page. */ Textblock::Word *Textblock::addWord (int width, int ascent, int descent, - bool canBeHyphenated, - core::style::Style *style) + short flags, core::style::Style *style) { words->increase (); Word *word = words->getLastRef (); - fillWord (word, width, ascent, descent, canBeHyphenated, style); + fillWord (word, width, ascent, descent, flags, style); return word; } void Textblock::fillWord (Word *word, int width, int ascent, int descent, - bool canBeHyphenated, core::style::Style *style) + short flags, core::style::Style *style) { word->size.width = width; word->size.ascent = ascent; @@ -1433,7 +1461,7 @@ void Textblock::fillWord (Word *word, int width, int ascent, int descent, word->hyphenWidth = 0; word->badnessAndPenalty.setPenalty (PENALTY_PROHIBIT_BREAK); word->content.space = false; - word->flags = canBeHyphenated ? Word::CAN_BE_HYPHENATED : 0; + word->flags = flags; word->style = style; word->spaceStyle = style; @@ -1561,13 +1589,12 @@ void Textblock::addText (const char *text, size_t len, // Count dividing characters. int numParts = 1; - for (int i = 0; i < (int)len; - i < (int)len && (i = layout->nextGlyph (text, i))) { + for (const char *s = text; s; s = nextUtf8Char (s, text + len - s)) { int foundDiv = -1; for (int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) { int lDiv = strlen (divChars[j].s); - if (i <= (int)len - lDiv) { - if (memcmp (text + i, divChars[j].s, lDiv * sizeof (char)) == 0) + if (s <= text + len - lDiv) { + if (memcmp (s, divChars[j].s, lDiv * sizeof (char)) == 0) foundDiv = j; } } @@ -1585,7 +1612,7 @@ void Textblock::addText (const char *text, size_t len, // be hyphenated automatically. core::Requisition size; calcTextSize (text, len, style, &size); - addText0 (text, len, true, style, &size); + addText0 (text, len, Word::CAN_BE_HYPHENATED, style, &size); } else { PRINTF ("HYPHENATION: '"); for (size_t i = 0; i < len; i++) @@ -1602,13 +1629,12 @@ void Textblock::addText (const char *text, size_t len, partStart[0] = 0; partEnd[numParts - 1] = len; - for (int i = 0; i < (int)len; - i < (int)len && (i = layout->nextGlyph (text, i))) { + for (const char *s = text; s; s = nextUtf8Char (s, text + len - s)) { int foundDiv = -1; for (int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) { int lDiv = strlen (divChars[j].s); - if (i <= (int)len - lDiv) { - if (memcmp (text + i, divChars[j].s, lDiv * sizeof (char)) == 0) + if (s <= text + len - lDiv) { + if (memcmp (s, divChars[j].s, lDiv * sizeof (char)) == 0) foundDiv = j; } } @@ -1626,8 +1652,8 @@ void Textblock::addText (const char *text, size_t len, unbreakableForMinWidth[n] = divChars[foundDiv].unbreakableForMinWidth; canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated; - partEnd[n] = i; - partStart[n + 1] = i + lDiv; + partEnd[n] = s - text; + partStart[n + 1] = s - text + lDiv; n++; totalLenCharRemoved += lDiv; } else { @@ -1641,8 +1667,8 @@ void Textblock::addText (const char *text, size_t len, unbreakableForMinWidth[n] = divChars[foundDiv].unbreakableForMinWidth; canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated; - partEnd[n] = i; - partStart[n + 1] = i; + partEnd[n] = s - text; + partStart[n + 1] = s - text; n++; } @@ -1653,8 +1679,8 @@ void Textblock::addText (const char *text, size_t len, unbreakableForMinWidth[n] = divChars[foundDiv].unbreakableForMinWidth; canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated; - partEnd[n] = i + lDiv; - partStart[n + 1] = i + lDiv; + partEnd[n] = s - text + lDiv; + partStart[n + 1] = s - text + lDiv; n++; } } @@ -1699,18 +1725,33 @@ void Textblock::addText (const char *text, size_t len, // Finished! for (int i = 0; i < numParts; i++) { + short flags = 0; + + // If this parts adjoins at least one division characters, + // for which canBeHyphenated is set to false (this is the + // case for soft hyphens), do not hyphenate. + if (canBeHyphenated[i] && canBeHyphenated[i + 1]) + flags |= Word::CAN_BE_HYPHENATED; + + if(i < numParts - 1) { + if (charRemoved[i]) + flags |= Word::DIV_CHAR_AT_EOL; + + if (permDivChar[i]) + flags |= Word::PERM_DIV_CHAR; + if (unbreakableForMinWidth[i]) + flags |= Word::UNBREAKABLE_FOR_MIN_WIDTH; + + flags |= Word::DRAW_AS_ONE_TEXT; + } + addText0 (text + partStart[i], partEnd[i] - partStart[i], - // If this parts adjoins at least one division - // characters, for which canBeHyphenated is set to - // false (this is the case for soft hyphens), do - // not hyphenate. - canBeHyphenated[i] && canBeHyphenated[i + 1], - style, &wordSize[i]); - - PRINTF("H... [%d] '", i); - for (int j = partStart[i]; j < partEnd[i]; j++) - PUTCHAR(text[j]); - PRINTF("' added\n"); + flags, style, &wordSize[i]); + + //PRINTF("H... [%d] '", i); + //for (int j = partStart[i]; j < partEnd[i]; j++) + // PUTCHAR(text[j]); + //PRINTF("' added\n"); if(i < numParts - 1) { Word *word = words->getLastRef(); @@ -1719,7 +1760,7 @@ void Textblock::addText (const char *text, size_t len, .setPenalties (penalties[partPenaltyIndex[i]][0], penalties[partPenaltyIndex[i]][1]); - if (charRemoved[i]) { + if (charRemoved[i]) // Currently, only unconditional hyphens (UTF-8: // "\xe2\x80\x90") can be used. See also drawWord, last // section "if (drawHyphen)". @@ -1728,15 +1769,6 @@ void Textblock::addText (const char *text, size_t len, word->hyphenWidth = layout->textWidth (word->style->font, hyphenDrawChar, strlen (hyphenDrawChar)); - word->flags |= Word::DIV_CHAR_AT_EOL; - } - - if (permDivChar[i]) - word->flags |= Word::PERM_DIV_CHAR; - if (unbreakableForMinWidth[i]) - word->flags |= Word::UNBREAKABLE_FOR_MIN_WIDTH; - - word->flags |= Word::DRAW_AS_ONE_TEXT; accumulateWordData (words->size() - 1); correctLastWordExtremes (); @@ -1781,16 +1813,18 @@ void Textblock::calcTextSizes (const char *text, size_t textLen, /** * Add a word (without hyphens) to the page structure. */ -void Textblock::addText0 (const char *text, size_t len, bool canBeHyphenated, +void Textblock::addText0 (const char *text, size_t len, short flags, core::style::Style *style, core::Requisition *size) { //printf("[%p] addText0 ('", this); //for (size_t i = 0; i < len; i++) // putchar(text[i]); - //printf("', %s, ...)\n", canBeHyphenated ? "true" : "false"); + //printf("', "); + //printWordFlags (flags); + //printf (", ...)\n"); Word *word = addWord (size->width, size->ascent, size->descent, - canBeHyphenated, style); + flags, style); word->content.type = core::Content::TEXT; word->content.text = layout->textZone->strndup(text, len); @@ -1839,7 +1873,7 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) core::Requisition size; calcWidgetSize (widget, &size); Word *word = - addWord (size.width, size.ascent, size.descent, false, style); + addWord (size.width, size.ascent, size.descent, 0, style); word->content.type = core::Content::WIDGET_IN_FLOW; word->content.widget = widget; } @@ -2049,7 +2083,7 @@ void Textblock::addParbreak (int space, core::style::Style *style) return; } - word = addWord (0, 0, 0, false, style); + word = addWord (0, 0, 0, 0, style); word->content.type = core::Content::BREAK; word->badnessAndPenalty.setPenalty (PENALTY_FORCE_BREAK); word->content.breakSpace = space; @@ -2068,10 +2102,10 @@ void Textblock::addLinebreak (core::style::Style *style) // An <BR> in an empty line gets the height of the current font // (why would someone else place it here?), ... word = - addWord (0, style->font->ascent, style->font->descent, false, style); + addWord (0, style->font->ascent, style->font->descent, 0, style); else // ... otherwise, it has no size (and does not enlarge the line). - word = addWord (0, 0, 0, false, style); + word = addWord (0, 0, 0, 0, style); word->content.type = core::Content::BREAK; word->badnessAndPenalty.setPenalty (PENALTY_FORCE_BREAK); diff --git a/dw/textblock.hh b/dw/textblock.hh index 42dec369..6db3d014 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -353,6 +353,7 @@ protected: }; void printWordShort (Word *word); + void printWordFlags (short flags); void printWordWithFlags (Word *word); void printWord (Word *word); @@ -475,12 +476,13 @@ protected: void drawLine (Line *line, core::View *view, core::Rectangle *area); int findLineIndex (int y); int findLineOfWord (int wordIndex); + int findParagraphOfWord (int wordIndex); Word *findWord (int x, int y, bool *inSpace); - Word *addWord (int width, int ascent, int descent, bool canBeHyphenated, + Word *addWord (int width, int ascent, int descent, short flags, core::style::Style *style); void fillWord (Word *word, int width, int ascent, int descent, - bool canBeHyphenated, core::style::Style *style); + short flags, core::style::Style *style); void fillSpace (Word *word, core::style::Style *style); void setBreakOption (Word *word, core::style::Style *style); int textWidth (const char *text, int start, int len, @@ -672,7 +674,7 @@ protected: void removeChild (Widget *child); - void addText0 (const char *text, size_t len, bool canBeHyphenated, + void addText0 (const char *text, size_t len, short flags, core::style::Style *style, core::Requisition *size); void calcTextSizes (const char *text, size_t textLen, core::style::Style *style, diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index bbfe9777..aa7ce664 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -235,15 +235,22 @@ void Textblock::printWordShort (Word *word) } } +void Textblock::printWordFlags (short flags) +{ + printf ("%s:%s:%s:%s:%s", + (flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--", + (flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--", + (flags & Word::PERM_DIV_CHAR) ? "dp" : "--", + (flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--", + (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--"); +} + void Textblock::printWordWithFlags (Word *word) { printWordShort (word); - printf (" (flags = %s:%s:%s:%s:%s)", - (word->flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--", - (word->flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--", - (word->flags & Word::PERM_DIV_CHAR) ? "dp" : "--", - (word->flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--", - (word->flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--"); + printf (" (flags = "); + printWordFlags (word->flags); + printf (")"); } void Textblock::printWord (Word *word) @@ -689,9 +696,9 @@ void Textblock::handleWordExtremes (int wordIndex) core::Extremes wordExtremes; getWordExtremes (word, &wordExtremes); - //printf ("[%p] HANDLE_WORD_EXTREMES (%d):", this, wordIndex); + //printf ("[%p] HANDLE_WORD_EXTREMES (%d): ", this, wordIndex); //printWordWithFlags (word); - //printf ("=> %d / %d\n", wordExtremes.minWidth, wordExtremes.maxWidth); + //printf (" => %d / %d\n", wordExtremes.minWidth, wordExtremes.maxWidth); if (wordIndex == 0) { wordExtremes.minWidth += line1Offset; @@ -702,9 +709,9 @@ void Textblock::handleWordExtremes (int wordIndex) words->getRef(paragraphs->getLastRef()->lastWord) ->badnessAndPenalty.lineMustBeBroken (1)) { // Add a new paragraph. - Paragraph *prevPar = - paragraphs->size() == 0 ? NULL : paragraphs->getLastRef(); paragraphs->increase (); + Paragraph *prevPar = paragraphs->size() == 1 ? + NULL : paragraphs->getRef(paragraphs->size() - 2); Paragraph *par = paragraphs->getLastRef(); par->firstWord = par->lastWord = wordIndex; @@ -715,8 +722,11 @@ void Textblock::handleWordExtremes (int wordIndex) par->maxParMax = prevPar->maxParMax; } else par->maxParMin = par->maxParMax = 0; + + PRINTF (" new par: %d\n", paragraphs->size() - 1); } + PRINTF (" last par: %d\n", paragraphs->size() - 1); Paragraph *lastPar = paragraphs->getLastRef(); int corrDiffMin, corrDiffMax; @@ -747,8 +757,9 @@ void Textblock::handleWordExtremes (int wordIndex) lastPar->parMax += wordExtremes.maxWidth + word->hyphenWidth + corrDiffMax; lastPar->maxParMax = misc::max (lastPar->maxParMax, lastPar->parMax); - PRINTF (" => parMin = %d, parMax = %d\n", - lastPar->parMin, lastPar->parMax); + PRINTF (" => parMin = %d (max = %d), parMax = %d (max = %d)\n", + lastPar->parMin, lastPar->maxParMin, lastPar->parMax, + lastPar->maxParMax); lastPar->lastWord = wordIndex; } @@ -759,7 +770,9 @@ void Textblock::handleWordExtremes (int wordIndex) void Textblock::correctLastWordExtremes () { if (paragraphs->size() > 0) { - if (words->getLastRef()->badnessAndPenalty.lineCanBeBroken (1)) { + Word *word = words->getLastRef (); + if (word->badnessAndPenalty.lineCanBeBroken (1) && + (word->flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) == 0) { paragraphs->getLastRef()->parMin = 0; PRINTF (" => corrected; parMin = %d\n", paragraphs->getLastRef()->parMin); @@ -773,13 +786,13 @@ int Textblock::hyphenateWord (int wordIndex) Word *hyphenatedWord = words->getRef(wordIndex); char lang[3] = { hyphenatedWord->style->x_lang[0], hyphenatedWord->style->x_lang[1], 0 }; - Hyphenator *hyphenator = - Hyphenator::getHyphenator (layout->getPlatform (), lang); + Hyphenator *hyphenator = Hyphenator::getHyphenator (lang); PRINTF ("[%p] considering to hyphenate word %d, '%s', in language '%s'\n", this, wordIndex, words->getRef(wordIndex)->content.text, lang); int numBreaks; int *breakPos = - hyphenator->hyphenateWord (hyphenatedWord->content.text, &numBreaks); + hyphenator->hyphenateWord (layout->getPlatform (), + hyphenatedWord->content.text, &numBreaks); if (numBreaks > 0) { Word origWord = *hyphenatedWord; @@ -1146,12 +1159,20 @@ void Textblock::fillParagraphs () else firstWordOfLine = 0; - // Binary search would be faster, but there should not be many paragraphs - // in a text block (so that binary search may be even slower). - int parNo = 0; - while (paragraphs->size() - 1 > parNo && - paragraphs->getRef(parNo)->lastWord <= firstWordOfLine) - parNo++; + int parNo; + if (paragraphs->size() > 0 && + firstWordOfLine > paragraphs->getLastRef()->firstWord) + // A special case: the paragraphs list has been partly built, but + // not yet the paragraph containing the word in question. In + // this case, only the rest of the paragraphs list must be + // constructed. (Without this check, findParagraphOfWord would + // return -1 in this case, so that all paragraphs would be + // rebuilt.) + parNo = paragraphs->size (); + else + // If there are no paragraphs yet, findParagraphOfWord will return + // -1: use 0 then instead. + parNo = misc::max (0, findParagraphOfWord (firstWordOfLine)); paragraphs->setSize (parNo); diff --git a/lout/unicode.cc b/lout/unicode.cc index 38d71494..39d3a094 100644 --- a/lout/unicode.cc +++ b/lout/unicode.cc @@ -1,4 +1,7 @@ #include "unicode.hh" +#include "misc.hh" + +using namespace lout::misc; namespace lout { @@ -47,27 +50,93 @@ bool isAlpha (int ch) return ch < 0x500 && (alpha[ch / 8] & (1 << (ch & 7))); } -int decodeUtf8 (char *s) +int decodeUtf8 (const char *s) { if((s[0] & 0x80) == 0) return s[0]; - else { - int mask = 0xe0, bits = 0xc0, done = 0, ch = 0, i = 0; - for(int j = 1; !done && j < 7; - j++, mask = 0x80 | (mask >> 1), bits = 0x80 | (bits >> 1)) { - if(((unsigned char)s[i] & mask) == bits) { - done = 1; - ch = (unsigned char)s[i] & ~mask & 0xff; - i++; - for(int k = 0; k < j; k++) { - ch = (ch << 6) | ((unsigned char)s[i] & 0x3f); - i++; - } - } - } - - return ch; - } + else if((s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80) + return ((s[0] & 0x1f) << 6) | (s[1] & 0x3f); + else if((s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80) + return ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f); + else if((s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) + return ((s[0] & 0x0f) << 18) | ((s[1] & 0x3f) << 12) + | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f); + else + // Treat as ISO-8859-1 / ISO-8859-15 / Windows-1252 + return s[0]; +} + + +int decodeUtf8 (const char *s, int len) +{ + if(len >= 1 && (s[0] & 0x80) == 0) + return s[0]; + else if(len >= 2 && (s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80) + return ((s[0] & 0x1f) << 6) | (s[1] & 0x3f); + else if(len >= 3 && (s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80) + return ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f); + else if(len >= 4 && (s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) + return ((s[0] & 0x0f) << 18) | ((s[1] & 0x3f) << 12) + | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f); + else + // Treat as ISO-8859-1 / ISO-8859-15 / Windows-1252 + return s[0]; +} + +const char *nextUtf8Char (const char *s) +{ + const char *r; + + if (s == NULL || s[0] == 0) + r = NULL; + else if((s[0] & 0x80) == 0) + r = s + 1; + else if((s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80) + r = s + 2; + else if((s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80) + r = s + 3; + else if((s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) + r = s + 4; + else + // invalid UTF-8 sequence: treat as one byte. + r = s + 1; + + if (r && r[0] == 0) + return NULL; + else + return r; +} + +const char *nextUtf8Char (const char *s, int len) +{ + const char *r; + + if (s == NULL || len <= 0) + r = NULL; + else if(len >= 1 && (s[0] & 0x80) == 0) + r = s + 1; + else if(len >= 2 && (s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80) + r = s + 2; + else if(len >= 3 && (s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80) + r = s + 3; + else if(len >= 4 && (s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 + && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) + r = s + 4; + else + // invalid UTF-8 sequence: treat as one byte. + r = s + 1; + + if (r && r - s >= len) + return NULL; + else + return r; } } // namespace lout diff --git a/lout/unicode.hh b/lout/unicode.hh index 123e7aa3..cfde25e6 100644 --- a/lout/unicode.hh +++ b/lout/unicode.hh @@ -11,7 +11,13 @@ namespace unicode { bool isAlpha (int ch); -int decodeUtf8 (char *s); +int decodeUtf8 (const char *s); + +int decodeUtf8 (const char *s, int len); + +const char *nextUtf8Char (const char *s); + +const char *nextUtf8Char (const char *s, int len); } // namespace lout diff --git a/src/IO/dpi.c b/src/IO/dpi.c index 6f46b2ba..4b5a5aa2 100644 --- a/src/IO/dpi.c +++ b/src/IO/dpi.c @@ -614,10 +614,10 @@ static int Dpi_get_server_port(const char *server_name) * We have to ask 'dpid' (dpi daemon) for the port of the target dpi server. * Once we have it, then the proper file descriptor is returned (-1 on error). */ -static int Dpi_connect_socket(const char *server_name, int retry) +static int Dpi_connect_socket(const char *server_name) { struct sockaddr_in sin; - int sock_fd, err, dpi_port, ret=-1; + int sock_fd, dpi_port, ret = -1; char *cmd = NULL; /* Query dpid for the port number for this server */ @@ -636,16 +636,7 @@ static int Dpi_connect_socket(const char *server_name, int retry) if ((sock_fd = Dpi_make_socket_fd()) == -1) { perror("[dpi::socket]"); } else if (connect(sock_fd, (void*)&sin, sizeof(sin)) == -1) { - err = errno; - sock_fd = -1; MSG("[dpi::connect] errno:%d %s\n", errno, dStrerror(errno)); - if (retry) { - switch (err) { - case ECONNREFUSED: case EBADF: case ENOTSOCK: case EADDRNOTAVAIL: - sock_fd = Dpi_connect_socket(server_name, FALSE); - break; - } - } /* send authentication Key (the server closes sock_fd on error) */ } else if (!(cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "auth", SharedKey))) { @@ -677,7 +668,7 @@ void a_Dpi_ccc(int Op, int Branch, int Dir, ChainLink *Info, switch (Op) { case OpStart: if ((st = Dpi_blocking_start_dpid()) == 0) { - SockFD = Dpi_connect_socket(Data1, TRUE); + SockFD = Dpi_connect_socket(Data1); if (SockFD != -1) { int *fd = dNew(int, 1); *fd = SockFD; @@ -798,7 +789,7 @@ char *a_Dpi_send_blocking_cmd(const char *server_name, const char *cmd) return ret; } - if ((sock_fd = Dpi_connect_socket(server_name, TRUE)) == -1) { + if ((sock_fd = Dpi_connect_socket(server_name)) == -1) { MSG_ERR("[a_Dpi_send_blocking_cmd] Can't connect to server.\n"); } else if (Dpi_blocking_write(sock_fd, cmd, strlen(cmd)) == -1) { MSG_ERR("[a_Dpi_send_blocking_cmd] Can't send message.\n"); @@ -619,20 +619,21 @@ static int Auth_do_auth_dialog(const AuthParse_t *auth_parse, const DilloUrl *url) { int ret; - char *message; + char *title, *msg; AuthDialogData_t *data; const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic"; _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm); - message = dStrconcat("The server at ", URL_HOST(url), " requires a username" - " and password for \"", auth_parse->realm, "\".\n\n" - "Authentication scheme: ", typestr, NULL); + title = dStrconcat("Dillo: Password for ", auth_parse->realm, NULL); + msg = dStrconcat("The server at ", URL_HOST(url), " requires a username" + " and password for \"", auth_parse->realm, "\".\n\n" + "Authentication scheme: ", typestr, NULL); data = dNew(AuthDialogData_t, 1); data->auth_parse = auth_parse; data->url = a_Url_dup(url); - ret = a_Dialog_user_password(message, Auth_do_auth_dialog_cb, data); - dFree(message); + ret = a_Dialog_user_password(title, msg, Auth_do_auth_dialog_cb, data); + dFree(title); dFree(msg); a_Url_free((void *)data->url); dFree(data); return ret; diff --git a/src/dialog.cc b/src/dialog.cc index 3458adc2..94c31fb1 100644 --- a/src/dialog.cc +++ b/src/dialog.cc @@ -120,8 +120,11 @@ int EnterButton::handle(int e) /* * Display a message in a popup window. */ -void a_Dialog_msg(const char *msg) +void a_Dialog_msg(const char *title, const char *msg) { + if (!(title && *title)) + title = "Dillo: Message"; + fl_message_title(title); fl_message("%s", msg); } @@ -141,14 +144,17 @@ static void input_cb(Fl_Widget *button, void *number) * * Return value: string on success, NULL upon Cancel or Close window */ -const char *a_Dialog_input(const char *msg) +const char *a_Dialog_input(const char *title, const char *msg) { static Fl_Menu_Item *pm = 0; int ww = 450, wh = 130, gap = 10, ih = 60, bw = 80, bh = 30; input_answer = 0; - Fl_Window *window = new Fl_Window(ww,wh,"Ask"); + if (!(title && *title)) + title = "Dillo: Input"; + + Fl_Window *window = new Fl_Window(ww,wh,title); window->set_modal(); window->begin(); Fl_Group* ib = new Fl_Group(0,0,window->w(),window->h()); @@ -223,8 +229,11 @@ const char *a_Dialog_input(const char *msg) /* * Dialog for password */ -const char *a_Dialog_passwd(const char *msg) +const char *a_Dialog_passwd(const char *title, const char *msg) { + if (!(title && *title)) + title = "Dillo: Password"; + fl_message_title(title); return fl_password("%s", "", msg); } @@ -233,10 +242,10 @@ const char *a_Dialog_passwd(const char *msg) * * Return: pointer to chosen filename, or NULL on Cancel. */ -const char *a_Dialog_save_file(const char *msg, +const char *a_Dialog_save_file(const char *title, const char *pattern, const char *fname) { - return fl_file_chooser(msg, pattern, fname); + return fl_file_chooser(title, pattern, fname); } /* @@ -244,14 +253,14 @@ const char *a_Dialog_save_file(const char *msg, * * Return: pointer to chosen filename, or NULL on Cancel. */ -const char *a_Dialog_select_file(const char *msg, +const char *a_Dialog_select_file(const char *title, const char *pattern, const char *fname) { /* * FileChooser::type(MULTI) appears to allow multiple files to be selected, * but just follow save_file's path for now. */ - return a_Dialog_save_file(msg, pattern, fname); + return a_Dialog_save_file(title, pattern, fname); } /* @@ -259,12 +268,12 @@ const char *a_Dialog_select_file(const char *msg, * * Return: pointer to chosen filename, or NULL on Cancel. */ -char *a_Dialog_open_file(const char *msg, +char *a_Dialog_open_file(const char *title, const char *pattern, const char *fname) { const char *fc_name; - fc_name = fl_file_chooser(msg, pattern, fname); + fc_name = fl_file_chooser(title, pattern, fname); return (fc_name) ? a_Misc_escape_chars(fc_name, "% #") : NULL; } @@ -283,11 +292,14 @@ static void text_window_close_cb(Fl_Widget *, void *vtd) /* * Show a new window with the provided text */ -void a_Dialog_text_window(const char *txt, const char *title) +void a_Dialog_text_window(const char *title, const char *txt) { int wh = prefs.height, ww = prefs.width, bh = 30; - Fl_Window *window = new Fl_Window(ww, wh, title ? title : "Dillo text"); + if (!(title && *title)) + title = "Dillo: Text"; + + Fl_Window *window = new Fl_Window(ww, wh, title); Fl_Group::current(0); @@ -325,7 +337,7 @@ static void choice5_cb(Fl_Widget *button, void *number) * * Return value: 0 = dialog was cancelled, 1-5 = selected alternative. */ -int a_Dialog_choice5(const char *QuestionTxt, +int a_Dialog_choice5(const char *title, const char *msg, const char *alt1, const char *alt2, const char *alt3, const char *alt4, const char *alt5) { @@ -334,6 +346,11 @@ int a_Dialog_choice5(const char *QuestionTxt, int ww = 440, wh = 120, bw = 50, bh = 45, ih = 50, nb = 0; const char *txt[7]; + if (!(title && *title)) + title = "Dillo: Choice"; + if (!msg) + msg = ""; + txt[0] = txt[6] = NULL; txt[1] = alt1; txt[2] = alt2; txt[3] = alt3; txt[4] = alt4; txt[5] = alt5; @@ -346,7 +363,7 @@ int a_Dialog_choice5(const char *QuestionTxt, } ww = 140 + nb*(bw+10); - Fl_Window *window = new Fl_Window(ww,wh,"Choice5"); + Fl_Window *window = new Fl_Window(ww,wh,title); window->set_modal(); window->begin(); Fl_Group* ib = new Fl_Group(0,0,window->w(),window->h()); @@ -363,7 +380,7 @@ int a_Dialog_choice5(const char *QuestionTxt, o->label("?"); o->show(); - Fl_Box *box = new Fl_Box(60,0,ww-60,wh-bh, QuestionTxt); + Fl_Box *box = new Fl_Box(60,0,ww-60,wh-bh, msg); box->labelfont(FL_HELVETICA); box->labelsize(14); box->align(FL_ALIGN_WRAP); @@ -404,31 +421,34 @@ static void Dialog_user_password_cb(Fl_Widget *button, void *) * Call the callback with the result (OK or not) and the given user and * password if OK. */ -int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp) +int a_Dialog_user_password(const char *title, const char *msg, + UserPasswordCB cb, void *vp) { int ok = 0, window_h = 280, y, msg_w, msg_h; const int window_w = 300, input_x = 80, input_w = 200, input_h = 30, button_h = 30; /* window is resized below */ - Fl_Window *window = new Fl_Window(window_w,window_h,"Dillo User/Password"); + if (!(title && *title)) + title = "Dillo: User/Password"; + Fl_Window *window = new Fl_Window(window_w,window_h,title); Fl_Group::current(0); window->user_data(NULL); /* message */ y = 20; msg_w = window_w - 40; - Fl_Box *msg = new Fl_Box(20, y, msg_w, 100); /* resized below */ - msg->label(message); - msg->labelfont(FL_HELVETICA); - msg->labelsize(14); - msg->align(FL_ALIGN_INSIDE | FL_ALIGN_TOP_LEFT | FL_ALIGN_WRAP); + Fl_Box *msg_box = new Fl_Box(20, y, msg_w, 100); /* resized below */ + msg_box->label(msg); + msg_box->labelfont(FL_HELVETICA); + msg_box->labelsize(14); + msg_box->align(FL_ALIGN_INSIDE | FL_ALIGN_TOP_LEFT | FL_ALIGN_WRAP); - fl_font(msg->labelfont(), msg->labelsize()); + fl_font(msg_box->labelfont(), msg_box->labelsize()); msg_w -= 6; /* The label doesn't fill the entire box. */ - fl_measure(msg->label(), msg_w, msg_h, 0); /* fl_measure wraps at msg_w */ - msg->size(msg->w(), msg_h); - window->add(msg); + fl_measure(msg_box->label(), msg_w, msg_h, 0); /* fl_measure wraps at msg_w */ + msg_box->size(msg_box->w(), msg_h); + window->add(msg_box); /* inputs */ y += msg_h + 20; diff --git a/src/dialog.hh b/src/dialog.hh index 57b21849..8b3bc1b7 100644 --- a/src/dialog.hh +++ b/src/dialog.hh @@ -8,20 +8,21 @@ extern "C" { typedef void (*UserPasswordCB)(const char *user, const char *password, void *vp); -void a_Dialog_msg(const char *msg); -int a_Dialog_choice5(const char *QuestionTxt, +void a_Dialog_msg(const char *title, const char *msg); +int a_Dialog_choice5(const char *title, const char *msg, const char *alt1, const char *alt2, const char *alt3, const char *alt4, const char *alt5); -int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp); -const char *a_Dialog_input(const char *msg); -const char *a_Dialog_passwd(const char *msg); -const char *a_Dialog_save_file(const char *msg, +int a_Dialog_user_password(const char *title, const char *msg, + UserPasswordCB cb, void *vp); +const char *a_Dialog_input(const char *title, const char *msg); +const char *a_Dialog_passwd(const char *title, const char *msg); +const char *a_Dialog_save_file(const char *title, const char *pattern, const char *fname); -const char *a_Dialog_select_file(const char *msg, +const char *a_Dialog_select_file(const char *title, const char *pattern, const char *fname); -char *a_Dialog_open_file(const char *msg, +char *a_Dialog_open_file(const char *title, const char *pattern, const char *fname); -void a_Dialog_text_window(const char *txt, const char *title); +void a_Dialog_text_window(const char *title, const char *txt); #ifdef __cplusplus } diff --git a/src/dillo.cc b/src/dillo.cc index 9bab589c..3539ad42 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -26,6 +26,7 @@ #include <FL/Fl.H> #include <FL/Fl_Window.H> +#include <FL/fl_ask.H> #include <FL/fl_draw.H> #include "msg.h" @@ -397,6 +398,8 @@ int main(int argc, char **argv) // only way to set the // default font in fltk1.3 + fl_message_title_default("Dillo: Message"); + // Create a new UI/bw pair BrowserWindow *bw = a_UIcmd_browser_window_new(0, 0, xid, NULL); diff --git a/src/dpiapi.c b/src/dpiapi.c index 2068146c..d8980a17 100644 --- a/src/dpiapi.c +++ b/src/dpiapi.c @@ -49,7 +49,7 @@ static void Dpiapi_dialog_answer_cb(BrowserWindow *bw, int answer) */ void a_Dpiapi_dialog(BrowserWindow *bw, char *server, char *dpip_tag) { - char *question, *alt1, *alt2, *alt3, *alt4, *alt5; + char *title, *msg, *alt1, *alt2, *alt3, *alt4, *alt5; size_t dpip_tag_len; int ret; @@ -61,18 +61,19 @@ void a_Dpiapi_dialog(BrowserWindow *bw, char *server, char *dpip_tag) /* other options can be parsed the same way */ dpip_tag_len = strlen(dpip_tag); - question = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "msg"); + title = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "title"); + msg = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "msg"); alt1 = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "alt1"); alt2 = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "alt2"); alt3 = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "alt3"); alt4 = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "alt4"); alt5 = a_Dpip_get_attr_l(dpip_tag, dpip_tag_len, "alt5"); - ret = a_Dialog_choice5(question, alt1, alt2, alt3, alt4, alt5); + ret = a_Dialog_choice5(title, msg, alt1, alt2, alt3, alt4, alt5); /* As choice5 is modal, call the callback function directly. */ Dpiapi_dialog_answer_cb(bw, ret); dFree(alt1); dFree(alt2); dFree(alt3); dFree(alt4); dFree(alt5); - dFree(question); + dFree(title); dFree(msg); } diff --git a/src/form.cc b/src/form.cc index cf608cfc..8ec340bb 100644 --- a/src/form.cc +++ b/src/form.cc @@ -823,6 +823,14 @@ void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize) a_Html_stash_init(html); } +void Html_tag_close_option(DilloHtml *html) +{ + if (html->InFlags & IN_OPTION) { + Html_option_finish(html); + html->InFlags &= ~IN_OPTION; + } +} + /* * <BUTTON> */ @@ -884,7 +892,7 @@ void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize) // a_Dw_button_set_sensitive (DW_BUTTON (button), FALSE); HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ()); - HT2TB(html)->addWidget (embed, html->styleEngine->style ()); + HT2TB(html)->addWidget (embed, html->styleEngine->backgroundStyle ()); HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ()); S_TOP(html)->textblock = html->dw = page; diff --git a/src/form.hh b/src/form.hh index 297442e0..640e7e69 100644 --- a/src/form.hh +++ b/src/form.hh @@ -57,6 +57,7 @@ void Html_tag_close_textarea(DilloHtml *html); void Html_tag_open_select(DilloHtml *html, const char *tag, int tagsize); void Html_tag_close_select(DilloHtml *html); void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize); +void Html_tag_close_option(DilloHtml *html); void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize); void Html_tag_close_button(DilloHtml *html); diff --git a/src/html.cc b/src/html.cc index b1d10b45..f80d7954 100644 --- a/src/html.cc +++ b/src/html.cc @@ -3197,7 +3197,7 @@ const TagInfo Tags[] = { {"object", B8(111101),'R',2, Html_tag_open_object, NULL, NULL}, {"ol", B8(011010),'R',2, Html_tag_open_ol, NULL, NULL}, /* optgroup */ - {"option", B8(010001),'O',1, Html_tag_open_option, NULL, NULL}, + {"option", B8(010001),'O',1, Html_tag_open_option,NULL,Html_tag_close_option}, {"p", B8(010110),'O',1, Html_tag_open_p, NULL, NULL}, /* param 010001 'F' */ {"pre", B8(010110),'R',2, Html_tag_open_pre, NULL, Html_tag_close_pre}, @@ -487,7 +487,8 @@ static void Nav_reload_callback(void *data) confirmed = 1; } else if (URL_FLAGS(h_url) & URL_Post) { /* Attempt to repost data, let's confirm... */ - choice = a_Dialog_choice5("Repost form data?", + choice = a_Dialog_choice5("Dillo: Repost form?", + "Repost form data?", "No", "Yes", "Cancel", NULL, NULL); confirmed = (choice == 2); /* "Yes" */ } diff --git a/src/plain.cc b/src/plain.cc index 4da618e4..d63ce6cf 100644 --- a/src/plain.cc +++ b/src/plain.cc @@ -136,14 +136,17 @@ bool DilloPlain::PlainLinkReceiver::press (Widget *widget, int, int, int, int, void DilloPlain::addLine(char *Buf, uint_t BufSize) { int len; - char buf[128]; + char buf[129]; char *end = Buf + BufSize; if (BufSize > 0) { // Limit word length to avoid X11 coordinate // overflow with extremely long lines. - while ((len = a_Misc_expand_tabs(&Buf, end, buf, sizeof(buf)))) + while ((len = a_Misc_expand_tabs(&Buf, end, buf, sizeof(buf) - 1))) { + assert ((uint_t)len < sizeof(buf)); + buf[len] = '\0'; DW2TB(dw)->addText(buf, len, widgetStyle); + } } else { // Add dummy word for empty lines - otherwise the parbreak is ignored. DW2TB(dw)->addText("", 0, widgetStyle); diff --git a/src/tipwin.cc b/src/tipwin.cc index 1b6d91a2..d71f2a4e 100644 --- a/src/tipwin.cc +++ b/src/tipwin.cc @@ -1,3 +1,7 @@ +// tipwin.cc is derived from "Fl_Slider with a floating tooltip to show +// current value" at http://seriss.com/people/erco/fltk/#SliderTooltip by +// Greg Ercolano. + #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/src/uicmd.cc b/src/uicmd.cc index c00b01e6..de90748f 100644 --- a/src/uicmd.cc +++ b/src/uicmd.cc @@ -289,9 +289,15 @@ UI *CustTabs::add_new_tab(UI *old_ui, int focus) if (focus) { switch_tab(btn); - } else if (num_tabs() == 2) { - // no focus and tabbar added: redraw current page - Wizard->redraw(); + } else { // no focus + // set focus counter + increase_focus_counter(); + btn->focus_num(focus_counter); + + if (num_tabs() == 2) { + // tabbar added: redraw current page + Wizard->redraw(); + } } if (num_tabs() == 1) btn->hide(); @@ -476,7 +482,8 @@ static void win_cb (Fl_Widget *w, void *cb_data) { int choice = 1, ntabs = tabs->num_tabs(); if (prefs.show_quit_dialog && ntabs > 1) - choice = a_Dialog_choice5("Window contains more than one tab.", + choice = a_Dialog_choice5("Dillo: Close window?", + "Window contains more than one tab.", "Close", "Cancel", NULL, NULL, NULL); if (choice == 1) while (ntabs-- > 0) @@ -616,8 +623,9 @@ void a_UIcmd_close_all_bw(void *) int choice = 1; if (prefs.show_quit_dialog && a_Bw_num() > 1) - choice = a_Dialog_choice5("More than one open tab or window.", - "Quit", "Cancel", NULL, NULL, NULL); + choice = a_Dialog_choice5("Dillo: Quit?", + "More than one open tab or window.", + "Quit", "Cancel", NULL, NULL, NULL); if (choice == 1) while ((bw = a_Bw_get(0))) a_UIcmd_close_bw((void*)bw); @@ -860,7 +868,7 @@ void a_UIcmd_save(void *vbw) */ const char *a_UIcmd_select_file() { - return a_Dialog_select_file("Select a File", NULL, NULL); + return a_Dialog_select_file("Dillo: Select a File", NULL, NULL); } /* @@ -893,7 +901,7 @@ void a_UIcmd_open_file(void *vbw) char *name; DilloUrl *url; - name = a_Dialog_open_file("Open File", NULL, ""); + name = a_Dialog_open_file("Dillo: Open File", NULL, ""); if (name) { url = a_Url_new(name, "file:"); @@ -947,7 +955,7 @@ void a_UIcmd_search_dialog(void *vbw) { const char *query; - if ((query = a_Dialog_input("Search the Web:"))) { + if ((query = a_Dialog_input("Dillo: Search", "Search the Web:"))) { char *url_str = UIcmd_make_search_str(query); a_UIcmd_open_urlstr(vbw, url_str); dFree(url_str); @@ -960,9 +968,10 @@ void a_UIcmd_search_dialog(void *vbw) const char *a_UIcmd_get_passwd(const char *user) { const char *passwd; - char *prompt = dStrconcat("Password for user \"", user, "\"", NULL); - passwd = a_Dialog_passwd(prompt); - dFree(prompt); + const char *title = "Dillo: Password"; + char *msg = dStrconcat("Password for user \"", user, "\"", NULL); + passwd = a_Dialog_passwd(title, msg); + dFree(msg); return passwd; } @@ -977,7 +986,7 @@ void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url) a_UIcmd_set_save_dir(prefs.save_dir); SuggestedName = UIcmd_make_save_filename(URL_STR(url)); - if ((name = a_Dialog_save_file("Save Link as File", NULL, SuggestedName))) { + if ((name = a_Dialog_save_file("Dillo: Save Link as File", NULL, SuggestedName))) { MSG("a_UIcmd_save_link: %s\n", name); a_Nav_save_url(bw, url, name); } @@ -1099,9 +1108,9 @@ void a_UIcmd_view_page_bugs(void *vbw) BrowserWindow *bw = (BrowserWindow*)vbw; if (bw->num_page_bugs > 0) { - a_Dialog_text_window(bw->page_bugs->str, "Detected HTML errors"); + a_Dialog_text_window("Dillo: Detected HTML errors", bw->page_bugs->str); } else { - a_Dialog_msg("Zero detected HTML errors!"); + a_Dialog_msg("Dillo: Valid HTML!", "Zero detected HTML errors!"); } } diff --git a/test/Makefile.am b/test/Makefile.am index ab4c98b0..53e3d4ed 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,12 +20,12 @@ noinst_PROGRAMS = \ dw-imgbuf-mem-test \ dw-resource-test \ dw-ui-test \ - fltk-browser \ shapes \ cookies \ liang \ trie \ - notsosimplevector + notsosimplevector \ + unicode-test dw_anchors_test_SOURCES = dw_anchors_test.cc dw_anchors_test_LDADD = \ @@ -159,9 +159,6 @@ dw_ui_test_LDADD = \ $(top_builddir)/lout/liblout.a \ @LIBFLTK_LIBS@ -fltk_browser_SOURCES = fltk_browser.cc -fltk_browser_LDADD = @LIBFLTK_LIBS@ - shapes_SOURCES = shapes.cc shapes_LDADD = \ $(top_builddir)/dw/libDw-core.a \ @@ -193,3 +190,9 @@ trie_LDADD = \ notsosimplevector_SOURCES = notsosimplevector.cc notsosimplevector_LDADD = $(top_builddir)/lout/liblout.a + +unicode_test_SOURCES = unicode_test.cc + +unicode_test_LDADD = \ + $(top_builddir)/lout/liblout.a \ + @LIBFLTK_LIBS@ diff --git a/test/cookies.c b/test/cookies.c index 1468c248..5461e77e 100644 --- a/test/cookies.c +++ b/test/cookies.c @@ -368,10 +368,10 @@ static int Dpi_get_server_port(const char *server_name) } -static int Dpi_connect_socket(const char *server_name, int retry) +static int Dpi_connect_socket(const char *server_name) { struct sockaddr_in sin; - int sock_fd, err, dpi_port, ret=-1; + int sock_fd, dpi_port, ret = -1; char *cmd = NULL; /* Query dpid for the port number for this server */ @@ -390,16 +390,7 @@ static int Dpi_connect_socket(const char *server_name, int retry) if ((sock_fd = Dpi_make_socket_fd()) == -1) { perror("[dpi::socket]"); } else if (connect(sock_fd, (void*)&sin, sizeof(sin)) == -1) { - err = errno; - sock_fd = -1; MSG("[dpi::connect] errno:%d %s\n", errno, dStrerror(errno)); - if (retry) { - switch (err) { - case ECONNREFUSED: case EBADF: case ENOTSOCK: case EADDRNOTAVAIL: - sock_fd = Dpi_connect_socket(server_name, FALSE); - break; - } - } /* send authentication Key (the server closes sock_fd on error) */ } else if (!(cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "auth", SharedKey))) { @@ -425,7 +416,7 @@ char *a_Dpi_send_blocking_cmd(const char *server_name, const char *cmd) return ret; } - if ((sock_fd = Dpi_connect_socket(server_name, TRUE)) == -1) { + if ((sock_fd = Dpi_connect_socket(server_name)) == -1) { MSG_ERR("[a_Dpi_send_blocking_cmd] Can't connect to server.\n"); } else if (Dpi_blocking_write(sock_fd, cmd, strlen(cmd)) == -1) { MSG_ERR("[a_Dpi_send_blocking_cmd] Can't send message.\n"); diff --git a/test/fltk_browser.cc b/test/fltk_browser.cc deleted file mode 100644 index bdbec72c..00000000 --- a/test/fltk_browser.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 <FL/Fl_Window.H> -#include <FL/Fl_Multi_Browser.H> -#include <FL/Fl.H> - -int main (int argc, char *argv[]) -{ - Fl_Window *window = new Fl_Window (300, 300, "FLTK Browser"); - window->box(FL_NO_BOX); - window->begin (); - Fl_Multi_Browser *browser = new Fl_Multi_Browser (0, 0, 300, 300); - browser->begin (); - - for (int i = 0; i < 10; i++) { - browser->add("first"); - browser->add("second"); - browser->add("third"); - } - - window->resizable(browser); - window->show(); - return Fl::run(); -} diff --git a/test/liang.cc b/test/liang.cc index b1161d9f..a1bc2442 100644 --- a/test/liang.cc +++ b/test/liang.cc @@ -4,10 +4,10 @@ void hyphenateWord (dw::core::Platform *p, const char *word) { - dw::Hyphenator *h = dw::Hyphenator::getHyphenator (p, "de"); + dw::Hyphenator *h = dw::Hyphenator::getHyphenator ("de"); int numBreaks; - int *breakPos = h->hyphenateWord (word, &numBreaks); + int *breakPos = h->hyphenateWord (p, word, &numBreaks); for (int i = 0; i < numBreaks + 1; i++) { if (i != 0) printf (" \xc2\xad "); diff --git a/test/trie.cc b/test/trie.cc index 628daabf..41b56c70 100644 --- a/test/trie.cc +++ b/test/trie.cc @@ -1,10 +1,7 @@ -#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); @@ -12,6 +9,6 @@ int main (int argc, char *argv[]) /* Use pack = 1024 to create a really small trie - can take a while. */ - dw::Hyphenator hyphenator (&p, argv[1], NULL, 1024); + dw::Hyphenator hyphenator (argv[1], NULL, 1024); hyphenator.saveTrie (stdout); } diff --git a/test/unicode_test.cc b/test/unicode_test.cc new file mode 100644 index 00000000..31ede6ba --- /dev/null +++ b/test/unicode_test.cc @@ -0,0 +1,39 @@ +#include <string.h> +#include <stdio.h> +#include <FL/fl_utf8.h> +#include "../lout/unicode.hh" + +using namespace lout::unicode; + +int main (int argc, char *argv[]) +{ + // 0-terminated string + const char *t1 = "abcäöüабв−‐"; + + // not 0-terminated; copy from 0-terminated + int t2len = strlen (t1); + char t2[t2len]; + for (int i = 0; i < t2len; i++) + t2[i] = t1[i]; + + puts ("===== misc::unicode, 0-terminated ====="); + for (const char *s = t1; s; s = nextUtf8Char (s)) + printf ("%3d -> U+%04x ('%s')\n", (int)(s - t1), decodeUtf8(s), s); + + puts ("===== Fltk, 0-terminated ====="); + for (const char *s = t1; *s; s = fl_utf8fwd (s + 1, t1, t1 + strlen (t1))) + printf ("%3d -> U+%04x ('%s')\n", (int)(s - t1), decodeUtf8(s), s); + + puts ("===== misc::unicode, not 0-terminated ====="); + for (const char *s = t2; s; s = nextUtf8Char (s, t2len - (s - t2))) + printf ("%3d -> U+%04x\n", (int)(s - t2), + decodeUtf8(s, t2len - (s - t2))); + + puts ("===== Fltk, not 0-terminated ====="); + for (const char *s = t2; *s; + s - t2 < t2len && (s = fl_utf8fwd (s + 1, t2, t2 + t2len))) + printf ("%3d -> U+%04x\n", (int)(s - t2), + decodeUtf8(s, t2len - (s - t2))); + + return 0; +} |