bump crengine: word spacing and hyphenation tweaks

Includes:
- New option to tune word spacing: space width scale percent
- Text: look for hyphenation in more words if needed
- CSS: fix "hyphens:none" should override inherited "hyphens:auto"
- getHtml(): grab dir= and lang= attributes from upper nodes

Replace our Word Gap/Space condensing toggle/setting with
a new Word Spacing toggle/setting, made of 2 values:
- 1st number scales the normal width of spaces in all font
  (100% uses the font space width untouched)
- 2nd number applies after the 1st has been applied, and
  tells how much these spaces can additionally be condensed
  to make more text fit on a line.
pull/5658/head
poire-z 5 years ago
parent e4dd1826fa
commit 5541d5f5d3

@ -106,9 +106,9 @@ read_globals = {
"DCREREADER_CONFIG_LINE_SPACE_PERCENT_LARGE", "DCREREADER_CONFIG_LINE_SPACE_PERCENT_LARGE",
"DCREREADER_CONFIG_LINE_SPACE_PERCENT_X_LARGE", "DCREREADER_CONFIG_LINE_SPACE_PERCENT_X_LARGE",
"DCREREADER_CONFIG_LINE_SPACE_PERCENT_XX_LARGE", "DCREREADER_CONFIG_LINE_SPACE_PERCENT_XX_LARGE",
"DCREREADER_CONFIG_WORD_GAP_SMALL", "DCREREADER_CONFIG_WORD_SPACING_SMALL",
"DCREREADER_CONFIG_WORD_GAP_MEDIUM", "DCREREADER_CONFIG_WORD_SPACING_MEDIUM",
"DCREREADER_CONFIG_WORD_GAP_LARGE", "DCREREADER_CONFIG_WORD_SPACING_LARGE",
"DMINIBAR_TOC_MARKER_WIDTH", "DMINIBAR_TOC_MARKER_WIDTH",
"DMINIBAR_CONTAINER_HEIGHT", "DMINIBAR_CONTAINER_HEIGHT",
"DMINIBAR_FONT_SIZE", "DMINIBAR_FONT_SIZE",

@ -1 +1 @@
Subproject commit 91ecbd255a27cd373cabf3f161d2d599221f36fb Subproject commit ad55106331a726e29c630ba09f75c998b94b4708

@ -168,10 +168,19 @@ DCREREADER_CONFIG_LINE_SPACE_PERCENT_LARGE = 120
DCREREADER_CONFIG_LINE_SPACE_PERCENT_X_LARGE = 125 DCREREADER_CONFIG_LINE_SPACE_PERCENT_X_LARGE = 125
DCREREADER_CONFIG_LINE_SPACE_PERCENT_XX_LARGE = 130 DCREREADER_CONFIG_LINE_SPACE_PERCENT_XX_LARGE = 130
-- word gap percentage -- word spacing percentages
DCREREADER_CONFIG_WORD_GAP_SMALL = 50 -- 1st number scales the normal width of spaces in all font
DCREREADER_CONFIG_WORD_GAP_MEDIUM = 75 -- (100% uses the font space width untouched)
DCREREADER_CONFIG_WORD_GAP_LARGE = 100 -- 2nd number applies after the 1st has been applied, and
-- tells how much these spaces can additionally be condensed
-- to make more text fit on a line.
-- So, {80,50} can reduce the width of a space up to 40% of its
-- regular width. {99, 100} allows reducing it by at least 1px.
-- (These replace the old settings DCREREADER_CONFIG_WORD_GAP_*,
-- with the equivalence: new_option = { 100, old_option }.)
DCREREADER_CONFIG_WORD_SPACING_SMALL = {75, 50}
DCREREADER_CONFIG_WORD_SPACING_MEDIUM = {95, 75}
DCREREADER_CONFIG_WORD_SPACING_LARGE = {100, 90}
-- crereader progress bar (no longer needed) -- crereader progress bar (no longer needed)
-- 0 for top "full" progress bar -- 0 for top "full" progress bar

@ -130,9 +130,9 @@ function ReaderFont:onReadSettings(config)
or G_reader_settings:readSetting("copt_font_kerning") or 3 -- harfbuzz (slower, but needed for proper arabic) or G_reader_settings:readSetting("copt_font_kerning") or 3 -- harfbuzz (slower, but needed for proper arabic)
self.ui.document:setFontKerning(self.font_kerning) self.ui.document:setFontKerning(self.font_kerning)
self.space_condensing = config:readSetting("space_condensing") self.word_spacing = config:readSetting("word_spacing")
or G_reader_settings:readSetting("copt_space_condensing") or 75 or G_reader_settings:readSetting("copt_word_spacing") or {95, 75}
self.ui.document:setSpaceCondensing(self.space_condensing) self.ui.document:setWordSpacing(self.word_spacing)
self.line_space_percent = config:readSetting("line_space_percent") self.line_space_percent = config:readSetting("line_space_percent")
or G_reader_settings:readSetting("copt_line_spacing") or G_reader_settings:readSetting("copt_line_spacing")
@ -241,9 +241,9 @@ function ReaderFont:onSetFontKerning(mode)
return true return true
end end
function ReaderFont:onSetSpaceCondensing(space) function ReaderFont:onSetWordSpacing(values)
self.space_condensing = space self.word_spacing = values
self.ui.document:setSpaceCondensing(space) self.ui.document:setWordSpacing(values)
self.ui:handleEvent(Event:new("UpdatePos")) self.ui:handleEvent(Event:new("UpdatePos"))
return true return true
end end
@ -267,7 +267,7 @@ function ReaderFont:onSaveSettings()
self.ui.doc_settings:saveSetting("font_embolden", self.font_embolden) self.ui.doc_settings:saveSetting("font_embolden", self.font_embolden)
self.ui.doc_settings:saveSetting("font_hinting", self.font_hinting) self.ui.doc_settings:saveSetting("font_hinting", self.font_hinting)
self.ui.doc_settings:saveSetting("font_kerning", self.font_kerning) self.ui.doc_settings:saveSetting("font_kerning", self.font_kerning)
self.ui.doc_settings:saveSetting("space_condensing", self.space_condensing) self.ui.doc_settings:saveSetting("word_spacing", self.word_spacing)
self.ui.doc_settings:saveSetting("line_space_percent", self.line_space_percent) self.ui.doc_settings:saveSetting("line_space_percent", self.line_space_percent)
self.ui.doc_settings:saveSetting("gamma_index", self.gamma_index) self.ui.doc_settings:saveSetting("gamma_index", self.gamma_index)
end end

@ -703,11 +703,16 @@ function CreDocument:setFontKerning(mode)
self._document:setIntProperty("font.kerning.mode", mode) self._document:setIntProperty("font.kerning.mode", mode)
end end
-- min space condensing percent (how much we can decrease a space width to function CreDocument:setWordSpacing(values)
-- make text fit on a line) 25...100% -- values should be a table of 2 numbers (e.g.: { 90, 75 })
function CreDocument:setSpaceCondensing(value) -- - space width scale percent (hard scale the width of each space char in
logger.dbg("CreDocument: set space condensing", value) -- all fonts - 100 to use the normal font space glyph width unchanged).
self._document:setIntProperty("crengine.style.space.condensing.percent", value) -- - min space condensing percent (how much we can additionally decrease
-- a space width to make text fit on a line).
logger.dbg("CreDocument: set space width scale", values[1])
self._document:setIntProperty("crengine.style.space.width.scale.percent", values[1])
logger.dbg("CreDocument: set space condensing", values[2])
self._document:setIntProperty("crengine.style.space.condensing.percent", values[2])
end end
function CreDocument:setStyleSheet(new_css_file, appended_css_content ) function CreDocument:setStyleSheet(new_css_file, appended_css_content )

@ -277,8 +277,10 @@ Note that your selected font size is not affected by this setting.]]),
}, },
name_text_hold_callback = optionsutil.showValues, name_text_hold_callback = optionsutil.showValues,
-- used by showValues -- used by showValues
name_text_suffix = "%",
name_text_true_values = true, name_text_true_values = true,
show_true_value_func = function(val) -- add "%"
return string.format("%d%%", val)
end,
}, },
} }
}, },
@ -399,26 +401,27 @@ Note that your selected font size is not affected by this setting.]]),
(Font Hinting may need to be adjusted for the best result with either kerning implementation.)]]), (Font Hinting may need to be adjusted for the best result with either kerning implementation.)]]),
}, },
{ {
name = "space_condensing", name = "word_spacing",
name_text = S.WORD_GAP, name_text = S.WORD_SPACING,
toggle = {S.SMALL, S.MEDIUM, S.LARGE}, toggle = {S.SMALL, S.MEDIUM, S.LARGE},
values = { values = {
DCREREADER_CONFIG_WORD_GAP_SMALL, DCREREADER_CONFIG_WORD_SPACING_SMALL,
DCREREADER_CONFIG_WORD_GAP_MEDIUM, DCREREADER_CONFIG_WORD_SPACING_MEDIUM,
DCREREADER_CONFIG_WORD_GAP_LARGE, DCREREADER_CONFIG_WORD_SPACING_LARGE,
}, },
default_value = DCREREADER_CONFIG_WORD_GAP_MEDIUM, default_value = DCREREADER_CONFIG_WORD_SPACING_MEDIUM,
args = { args = {
DCREREADER_CONFIG_WORD_GAP_SMALL, DCREREADER_CONFIG_WORD_SPACING_SMALL,
DCREREADER_CONFIG_WORD_GAP_MEDIUM, DCREREADER_CONFIG_WORD_SPACING_MEDIUM,
DCREREADER_CONFIG_WORD_GAP_LARGE, DCREREADER_CONFIG_WORD_SPACING_LARGE,
}, },
event = "SetSpaceCondensing", event = "SetWordSpacing",
help_text = _([[Tells the rendering engine how much to scale the width of each 'space' character in the text from its regular width, and how much it can additionally reduce them to make more words fit on a line (100% means no reduction).]]),
name_text_hold_callback = optionsutil.showValues, name_text_hold_callback = optionsutil.showValues,
-- used by showValues
name_text_suffix = "%",
name_text_true_values = true, name_text_true_values = true,
help_text = _([[Tells the rendering engine how much each 'space' character in the text can be reduced from its regular width to make words fit on a line (100% means no reduction).]]), show_true_value_func = function(val)
return string.format("%d%%, +%d%%", val[1], val[2])
end,
} }
} }
}, },

@ -19,32 +19,40 @@ function optionsutil.showValues(configurable, option, prefix)
local default = G_reader_settings:readSetting(prefix.."_"..option.name) local default = G_reader_settings:readSetting(prefix.."_"..option.name)
local current = configurable[option.name] local current = configurable[option.name]
local value_default, value_current local value_default, value_current
local suffix = option.name_text_suffix or ""
if option.name == "screen_mode" then if option.name == "screen_mode" then
current = Screen:getScreenMode() current = Screen:getScreenMode()
end end
local arg_table = {}
if option.toggle and option.values then if option.toggle and option.values then
-- build a table so we can see if current/default settings map
-- to a known setting with a name (in option.toggle)
local arg_table = {}
for i=1,#option.values do for i=1,#option.values do
arg_table[option.values[i]] = option.toggle[i] local val = option.values[i]
-- flatten table to a string for easy lookup via arg_table
if type(val) == "table" then val = table.concat(val, ",") end
arg_table[val] = option.toggle[i]
end end
end
if not default then
default = _("not set")
if option.toggle and option.values then
value_current = current
current = arg_table[current]
if not current then current = value_current end
end
elseif option.toggle and option.values then
value_current = current value_current = current
value_default = default if type(current) == "table" then current = table.concat(current, ",") end
default = arg_table[default]
current = arg_table[current] current = arg_table[current]
if not default then default = value_default end if not current then
if not current then current = value_current end current = option.name_text_true_values and _("custom") or value_current
end end
if option.labels and option.values then if option.show_true_value_func then
value_current = option.show_true_value_func(value_current)
end
if default then
value_default = default
if type(default) == "table" then default = table.concat(default, ",") end
default = arg_table[default]
if not default then
default = option.name_text_true_values and _("custom") or value_default
end
if option.show_true_value_func then
value_default = option.show_true_value_func(value_default)
end
end
elseif option.labels and option.values then
if option.more_options_param and option.more_options_param.value_table then if option.more_options_param and option.more_options_param.value_table then
if option.more_options_param.args_table then if option.more_options_param.args_table then
for k,v in pairs(option.more_options_param.args_table) do for k,v in pairs(option.more_options_param.args_table) do
@ -55,7 +63,7 @@ function optionsutil.showValues(configurable, option, prefix)
end end
end end
current = option.more_options_param.value_table[current] current = option.more_options_param.value_table[current]
if default ~= _("not set") then if default then
if option.more_options_param.args_table then if option.more_options_param.args_table then
for k,v in pairs(option.more_options_param.args_table) do for k,v in pairs(option.more_options_param.args_table) do
if v == default then if v == default then
@ -67,7 +75,7 @@ function optionsutil.showValues(configurable, option, prefix)
default = option.more_options_param.value_table[default] default = option.more_options_param.value_table[default]
end end
else else
if default ~= _("not set") then if default then
for i=1,#option.labels do for i=1,#option.labels do
if default == option.values[i] then if default == option.values[i] then
default = option.labels[i] default = option.labels[i]
@ -82,21 +90,30 @@ function optionsutil.showValues(configurable, option, prefix)
end end
end end
end end
elseif option.show_true_value_func and option.values then
current = option.show_true_value_func(current)
if default then
default = option.show_true_value_func(default)
end
end
if not default then
default = _("not set")
end end
local help_text = "" local help_text = ""
if option.help_text then if option.help_text then
help_text = T("\n%1\n", option.help_text) help_text = T("\n%1\n", option.help_text)
end end
local text local text
if option.name_text_true_values and option.toggle and option.values and value_default then if option.name_text_true_values and option.toggle and option.values then
text = T(_("%1:\n%2\nCurrent value: %3 (%6%5)\nDefault value: %4 (%7%5)"), option.name_text, help_text, if value_default then
current, default, suffix, value_current, value_default) text = T(_("%1\n%2\nCurrent value: %3 (%4)\nDefault value: %5 (%6)"), option.name_text, help_text,
elseif option.name_text_true_values and option.toggle and option.values and not value_default then current, value_current, default, value_default)
text = T(_("%1\n%2\nCurrent value: %3 (%6%5)\nDefault value: %4"), option.name_text, help_text, else
current, default, suffix, value_current) text = T(_("%1\n%2\nCurrent value: %3 (%4)\nDefault value: %5"), option.name_text, help_text,
current, value_current, default)
end
else else
text = T(_("%1\n%2\nCurrent value: %3%5\nDefault value: %4%5"), option.name_text, help_text, text = T(_("%1\n%2\nCurrent value: %3\nDefault value: %4"), option.name_text, help_text, current, default)
current, default, suffix)
end end
UIManager:show(InfoMessage:new{ text=text }) UIManager:show(InfoMessage:new{ text=text })
end end

@ -35,6 +35,21 @@ function SettingsMigration:migrateSettings(config)
-- Wipe it -- Wipe it
config:delSetting("copt_page_margins") config:delSetting("copt_page_margins")
end end
-- Space condensing to Word spacing
-- From a single number (space condensing) to a table of 2 numbers ({space width scale, space condensing}).
-- Be conservative and don't change space width scale: use 100%
if not config:readSetting("copt_word_spacing") and config:readSetting("copt_space_condensing") then
local space_condensing = config:readSetting("copt_space_condensing")
logger.info("Migrating old", cfg_class, "CRe space condensing:", space_condensing)
config:saveSetting("copt_word_spacing", { 100, space_condensing })
if cfg_class == "book" then
-- a bit messy that some settings are saved twice in DocSettings, with
-- and without a copt_ prefix, and they must be in sync
config:saveSetting("word_spacing", { 100, space_condensing })
end
end
end end
return SettingsMigration return SettingsMigration

@ -33,6 +33,7 @@ S.FONT_WEIGHT = _("Font Weight")
S.GAMMA = _("Gamma") S.GAMMA = _("Gamma")
S.FONT_HINT = _("Font Hinting") S.FONT_HINT = _("Font Hinting")
S.FONT_KERNING = _("Font Kerning") S.FONT_KERNING = _("Font Kerning")
S.WORD_SPACING = _("Word Spacing")
S.VIEW_MODE = _("View Mode") S.VIEW_MODE = _("View Mode")
S.EMBEDDED_STYLE = _("Embedded Style") S.EMBEDDED_STYLE = _("Embedded Style")
S.EMBEDDED_FONTS = _("Embedded Fonts") S.EMBEDDED_FONTS = _("Embedded Fonts")

@ -27,11 +27,15 @@ describe("defaults module", function()
assert.is_same("DFULL_SCREEN", Defaults.defaults_name[54]) assert.is_same("DFULL_SCREEN", Defaults.defaults_name[54])
assert.is_same("SEARCH_LIBRARY_PATH", Defaults.defaults_name[103]) assert.is_same("SEARCH_LIBRARY_PATH", Defaults.defaults_name[103])
assert.is_same("DTAP_ZONE_BACKWARD", Defaults.defaults_name[87]) assert.is_same("DTAP_ZONE_BACKWARD", Defaults.defaults_name[87])
assert.is_same("DCREREADER_CONFIG_WORD_GAP_LARGE", Defaults.defaults_name[47]) assert.is_same("DCREREADER_CONFIG_WORD_SPACING_LARGE", Defaults.defaults_name[47])
assert.is_same("DCREREADER_CONFIG_H_MARGIN_SIZES_XXX_LARGE", Defaults.defaults_name[20]) assert.is_same("DCREREADER_CONFIG_H_MARGIN_SIZES_XXX_LARGE", Defaults.defaults_name[20])
local fd = io.open(persistent_filename, "r") local fd = io.open(persistent_filename, "r")
assert.Equals( assert.Equals(
[[-- For configuration changes that persists between updates [[-- For configuration changes that persists between updates
DCREREADER_CONFIG_WORD_SPACING_LARGE = {
[1] = 100,
[2] = 90
}
SEARCH_LIBRARY_PATH = "" SEARCH_LIBRARY_PATH = ""
DTAP_ZONE_BACKWARD = { DTAP_ZONE_BACKWARD = {
["y"] = 0, ["y"] = 0,
@ -39,7 +43,6 @@ DTAP_ZONE_BACKWARD = {
["h"] = 1, ["h"] = 1,
["w"] = 0.25 ["w"] = 0.25
} }
DCREREADER_CONFIG_WORD_GAP_LARGE = 100
DCREREADER_CONFIG_H_MARGIN_SIZES_XXX_LARGE = { DCREREADER_CONFIG_H_MARGIN_SIZES_XXX_LARGE = {
[1] = 50, [1] = 50,
[2] = 50 [2] = 50
@ -64,6 +67,10 @@ DFULL_SCREEN = 1
fd = io.open(persistent_filename) fd = io.open(persistent_filename)
assert.Equals( assert.Equals(
[[-- For configuration changes that persists between updates [[-- For configuration changes that persists between updates
DCREREADER_CONFIG_WORD_SPACING_LARGE = {
[2] = 90,
[1] = 100
}
SEARCH_LIBRARY_PATH = "" SEARCH_LIBRARY_PATH = ""
DTAP_ZONE_BACKWARD = { DTAP_ZONE_BACKWARD = {
["y"] = 10, ["y"] = 10,
@ -71,7 +78,6 @@ DTAP_ZONE_BACKWARD = {
["h"] = 20.25, ["h"] = 20.25,
["w"] = 20.75 ["w"] = 20.75
} }
DCREREADER_CONFIG_WORD_GAP_LARGE = 100
DCREREADER_CONFIG_H_MARGIN_SIZES_XXX_LARGE = { DCREREADER_CONFIG_H_MARGIN_SIZES_XXX_LARGE = {
[2] = 50, [2] = 50,
[1] = 50 [1] = 50

@ -317,8 +317,8 @@ describe("Readerfooter module", function()
assert.are.same(362, footer.text_width) assert.are.same(362, footer.text_width)
footer:onPageUpdate(100) footer:onPageUpdate(100)
assert.are.same(186, footer.progress_bar.width) assert.are.same(194, footer.progress_bar.width)
assert.are.same(394, footer.text_width) assert.are.same(386, footer.text_width)
end) end)
it("should support chapter markers", function() it("should support chapter markers", function()

@ -184,15 +184,15 @@ describe("Readerrolling module", function()
describe("test changing word gap - space condensing", function() describe("test changing word gap - space condensing", function()
it("should show pages for different word gap", function() it("should show pages for different word gap", function()
readerui.document:setSpaceCondensing(100) readerui.document:setWordSpacing({100, 90})
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait")) readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
assert.are.same(252, readerui.document:getPageCount()) assert.are.same(252, readerui.document:getPageCount())
readerui.document:setSpaceCondensing(75) readerui.document:setWordSpacing({95, 75})
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait")) readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
assert.are.same(248, readerui.document:getPageCount()) assert.are.same(241, readerui.document:getPageCount())
readerui.document:setSpaceCondensing(50) readerui.document:setWordSpacing({75, 50})
readerui:handleEvent(Event:new("ChangeScreenMode", "portrait")) readerui:handleEvent(Event:new("ChangeScreenMode", "portrait"))
assert.are.same(235, readerui.document:getPageCount()) assert.are.same(231, readerui.document:getPageCount())
end) end)
end) end)

Loading…
Cancel
Save