aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Geerken <devnull@localhost>2012-12-17 11:49:07 +0100
committerSebastian Geerken <devnull@localhost>2012-12-17 11:49:07 +0100
commitf56b7cbad408c55319fb0c5dbcf09cb7468e5757 (patch)
treed03322b412e2686abbc525e8b30ce585a5533372
parent3b200df73761c2e50f5cd06255db191a07cd2942 (diff)
parent15b9a9eef6bfb7b532abb001bbc1bb5625937aed (diff)
Merge with main repo.
-rw-r--r--.hgignore1
-rw-r--r--AUTHORS1
-rw-r--r--ChangeLog2
-rw-r--r--doc/dw-line-breaking.doc54
-rw-r--r--dpi/downloads.cc14
-rw-r--r--dpi/ftp.c14
-rw-r--r--dpi/hello.c4
-rw-r--r--dpi/https.c42
-rw-r--r--dw/fltkcomplexbutton.cc27
-rw-r--r--dw/fltkcomplexbutton.hh6
-rw-r--r--dw/fltkui.cc16
-rw-r--r--dw/hyphenator.cc56
-rw-r--r--dw/hyphenator.hh21
-rw-r--r--dw/textblock.cc134
-rw-r--r--dw/textblock.hh8
-rw-r--r--dw/textblock_linebreaking.cc65
-rw-r--r--lout/unicode.cc105
-rw-r--r--lout/unicode.hh8
-rw-r--r--src/IO/dpi.c17
-rw-r--r--src/auth.c13
-rw-r--r--src/dialog.cc72
-rw-r--r--src/dialog.hh19
-rw-r--r--src/dillo.cc3
-rw-r--r--src/dpiapi.c9
-rw-r--r--src/form.cc10
-rw-r--r--src/form.hh1
-rw-r--r--src/html.cc2
-rw-r--r--src/nav.c3
-rw-r--r--src/plain.cc7
-rw-r--r--src/tipwin.cc4
-rw-r--r--src/uicmd.cc39
-rw-r--r--test/Makefile.am13
-rw-r--r--test/cookies.c15
-rw-r--r--test/fltk_browser.cc43
-rw-r--r--test/liang.cc4
-rw-r--r--test/trie.cc5
-rw-r--r--test/unicode_test.cc39
37 files changed, 537 insertions, 359 deletions
diff --git a/.hgignore b/.hgignore
index 9625732b..85b63866 100644
--- a/.hgignore
+++ b/.hgignore
@@ -36,7 +36,6 @@
^test/dw-table$
^test/dw-table-aligned$
^test/dw-ui-test$
-^test/fltk-browser$
^test/liang$
^test/notsosimplevector$
^test/trie$
diff --git a/AUTHORS b/AUTHORS
index b80e979b..e8f0b466 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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.
diff --git a/ChangeLog b/ChangeLog
index 805b6bec..a6b637b5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/dpi/ftp.c b/dpi/ftp.c
index 460c2f03..288f993c 100644
--- a/dpi/ftp.c
+++ b/dpi/ftp.c
@@ -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");
diff --git a/src/auth.c b/src/auth.c
index d6ff081b..c019b8ff 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -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},
diff --git a/src/nav.c b/src/nav.c
index 83a4fd9f..2cf51c23 100644
--- a/src/nav.c
+++ b/src/nav.c
@@ -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;
+}