diff --git a/assets/default/styles.css b/assets/default/styles.css
new file mode 100644
index 000000000..81cb01cfd
--- /dev/null
+++ b/assets/default/styles.css
@@ -0,0 +1,100 @@
+p {
+ fbreader-id: 51;
+ fbreader-name: xhtml-tag-p;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+pre {
+ fbreader-id: 9;
+ fbreader-name: "Preformatted text";
+ font-family: Monospace;
+ text-align: left;
+ hyphens: none;
+}
+
+code {
+ fbreader-id: 21;
+ fbreader-name: "Code";
+ font-family: Monospace;
+ hyphens: none;
+}
+
+h1 {
+ fbreader-id: 31;
+ fbreader-name: "Header 1";
+ font-size: 2em;
+ font-weight: bold;
+ margin-top: 0.67em;
+ margin-bottom: 0.67em;
+ hyphens: none;
+}
+
+h2 {
+ fbreader-id: 32;
+ fbreader-name: "Header 2";
+ font-size: 1.5em;
+ font-weight: bold;
+ margin-top: 0.83em;
+ margin-bottom: 0.83em;
+ hyphens: none;
+}
+
+h3 {
+ fbreader-id: 33;
+ fbreader-name: "Header 3";
+ font-size: 1.17em;
+ font-weight: bold;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+h4 {
+ fbreader-id: 34;
+ fbreader-name: "Header 4";
+ font-weight: bold;
+ margin-top: 1.33em;
+ margin-bottom: 1.33em;
+}
+
+h5 {
+ fbreader-id: 35;
+ fbreader-name: "Header 5";
+ font-size: 0.83em;
+ font-weight: bold;
+ margin-top: 1.67em;
+ margin-bottom: 1.67em;
+}
+
+h6 {
+ fbreader-id: 36;
+ fbreader-name: "Header 6";
+ font-size: 0.67em;
+ font-weight: bold;
+ margin-top: 2.33em;
+ margin-bottom: 2.33em;
+}
+
+em {
+ fbreader-id: 17;
+ fbreader-name: "Emphasis";
+ font-style: italic;
+}
+
+strong {
+ fbreader-id: 18;
+ fbreader-name: "Strong";
+ font-weight: bold;
+}
+
+i {
+ fbreader-id: 27;
+ fbreader-name: "Italic";
+ font-style: italic;
+}
+
+b {
+ fbreader-id: 28;
+ fbreader-name: "Bold";
+ font-weight: bold;
+}
diff --git a/assets/default/styles.xml b/assets/default/styles.xml
index f55f55d3e..7cef792f8 100644
--- a/assets/default/styles.xml
+++ b/assets/default/styles.xml
@@ -6,34 +6,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/jni/NativeFormats/fbreader/src/bookmodel/FBTextKind.h b/jni/NativeFormats/fbreader/src/bookmodel/FBTextKind.h
index 07388b4ad..b1264121f 100644
--- a/jni/NativeFormats/fbreader/src/bookmodel/FBTextKind.h
+++ b/jni/NativeFormats/fbreader/src/bookmodel/FBTextKind.h
@@ -65,6 +65,8 @@ enum FBTextKind {
H6 = 36,
EXTERNAL_HYPERLINK = 37,
//BOOK_HYPERLINK = 38,
+
+ XHTML_TAG_P = 51,
};
#endif /* __FBTEXTKIND_H__ */
diff --git a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp
index b2945eb30..458bef5a8 100644
--- a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp
+++ b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp
@@ -60,6 +60,10 @@ void XHTMLTagAction::endParagraph(XHTMLReader &reader) {
reader.endParagraph();
}
+void XHTMLTagAction::restartParagraph(XHTMLReader &reader) {
+ reader.restartParagraph();
+}
+
class XHTMLGlobalTagAction : public XHTMLTagAction {
private:
@@ -96,7 +100,11 @@ public:
class XHTMLTagParagraphAction : public XHTMLTextModeTagAction {
+private:
+ const FBTextKind myTextKind;
+
public:
+ XHTMLTagParagraphAction(FBTextKind textKind = (FBTextKind)-1);
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
void doAtEnd(XHTMLReader &reader);
};
@@ -286,8 +294,14 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut
void XHTMLTagLinkAction::doAtEnd(XHTMLReader&) {
}
+XHTMLTagParagraphAction::XHTMLTagParagraphAction(FBTextKind textKind) : myTextKind(textKind) {
+}
+
void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
if (!reader.myNewParagraphInProgress) {
+ if (myTextKind != -1) {
+ bookReader(reader).pushKind(myTextKind);
+ }
beginParagraph(reader);
reader.myNewParagraphInProgress = true;
}
@@ -295,6 +309,9 @@ void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
void XHTMLTagParagraphAction::doAtEnd(XHTMLReader &reader) {
endParagraph(reader);
+ if (myTextKind != -1) {
+ bookReader(reader).popKind();
+ }
}
void XHTMLTagBodyAction::doAtStart(XHTMLReader &reader, const char**) {
@@ -316,8 +333,7 @@ void XHTMLTagRestartParagraphAction::doAtStart(XHTMLReader &reader, const char**
if (reader.myCurrentParagraphIsEmpty) {
bookReader(reader).addFixedHSpace(1);
}
- endParagraph(reader);
- beginParagraph(reader);
+ restartParagraph(reader);
}
void XHTMLTagRestartParagraphAction::doAtEnd(XHTMLReader&) {
@@ -496,12 +512,15 @@ void XHTMLTagParagraphWithControlAction::doAtEnd(XHTMLReader &reader) {
void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) {
reader.myPreformatted = true;
+ bookReader(reader).pushKind(XHTML_TAG_P);
+ bookReader(reader).pushKind(PREFORMATTED);
beginParagraph(reader);
- bookReader(reader).addControl(PREFORMATTED, true);
}
void XHTMLTagPreAction::doAtEnd(XHTMLReader &reader) {
endParagraph(reader);
+ bookReader(reader).popKind();
+ bookReader(reader).popKind();
reader.myPreformatted = false;
}
@@ -543,7 +562,7 @@ void XHTMLReader::fillTagTable() {
//addAction("font", new XHTMLTagAction());
addAction("style", new XHTMLTagStyleAction());
- addAction("p", new XHTMLTagParagraphAction());
+ addAction("p", new XHTMLTagParagraphAction(XHTML_TAG_P));
addAction("h1", new XHTMLTagParagraphWithControlAction(H1));
addAction("h2", new XHTMLTagParagraphWithControlAction(H2));
addAction("h3", new XHTMLTagParagraphWithControlAction(H3));
@@ -787,41 +806,12 @@ void XHTMLReader::endElementHandler(const char *tag) {
void XHTMLReader::beginParagraph() {
myCurrentParagraphIsEmpty = true;
myModelReader.beginParagraph();
- bool doBlockSpaceBefore = false;
for (std::vector >::const_iterator it = myStyleEntryStack.begin(); it != myStyleEntryStack.end(); ++it) {
addTextStyleEntry(**it);
- doBlockSpaceBefore =
- doBlockSpaceBefore ||
- (*it)->isFeatureSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE);
- }
-
- if (doBlockSpaceBefore) {
- ZLTextStyleEntry blockingEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY);
- blockingEntry.setLength(
- ZLTextStyleEntry::LENGTH_SPACE_BEFORE,
- 0,
- ZLTextStyleEntry::SIZE_UNIT_PIXEL
- );
- addTextStyleEntry(blockingEntry);
}
}
void XHTMLReader::endParagraph() {
- bool doBlockSpaceAfter = false;
- for (std::vector >::const_iterator it = myStyleEntryStack.begin(); it != myStyleEntryStack.end() - myStylesToRemove; ++it) {
- doBlockSpaceAfter =
- doBlockSpaceAfter ||
- (*it)->isFeatureSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER);
- }
- if (doBlockSpaceAfter) {
- ZLTextStyleEntry blockingEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY);
- blockingEntry.setLength(
- ZLTextStyleEntry::LENGTH_SPACE_AFTER,
- 0,
- ZLTextStyleEntry::SIZE_UNIT_PIXEL
- );
- addTextStyleEntry(blockingEntry);
- }
for (; myStylesToRemove > 0; --myStylesToRemove) {
addTextStyleEntry(*myStyleEntryStack.back());
myStyleEntryStack.pop_back();
@@ -829,6 +819,25 @@ void XHTMLReader::endParagraph() {
myModelReader.endParagraph();
}
+void XHTMLReader::restartParagraph() {
+ ZLTextStyleEntry spaceAfterBlocker(ZLTextStyleEntry::STYLE_OTHER_ENTRY);
+ spaceAfterBlocker.setLength(
+ ZLTextStyleEntry::LENGTH_SPACE_AFTER,
+ 0,
+ ZLTextStyleEntry::SIZE_UNIT_PIXEL
+ );
+ addTextStyleEntry(spaceAfterBlocker);
+ endParagraph();
+ beginParagraph();
+ ZLTextStyleEntry spaceBeforeBlocker(ZLTextStyleEntry::STYLE_OTHER_ENTRY);
+ spaceBeforeBlocker.setLength(
+ ZLTextStyleEntry::LENGTH_SPACE_BEFORE,
+ 0,
+ ZLTextStyleEntry::SIZE_UNIT_PIXEL
+ );
+ addTextStyleEntry(spaceBeforeBlocker);
+}
+
void XHTMLReader::characterDataHandler(const char *text, std::size_t len) {
switch (myReadState) {
case XHTML_READ_NOTHING:
@@ -845,11 +854,9 @@ void XHTMLReader::characterDataHandler(const char *text, std::size_t len) {
if (myCurrentParagraphIsEmpty) {
myModelReader.addFixedHSpace(1);
}
- endParagraph();
+ restartParagraph();
text += 1;
len -= 1;
- beginParagraph();
- myModelReader.addControl(PREFORMATTED, true);
}
std::size_t spaceCounter = 0;
while (spaceCounter < len && std::isspace((unsigned char)*(text + spaceCounter))) {
diff --git a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h
index 38dae19d3..03ddb0406 100644
--- a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h
+++ b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h
@@ -59,6 +59,7 @@ protected:
static const std::string &pathPrefix(XHTMLReader &reader);
static void beginParagraph(XHTMLReader &reader);
static void endParagraph(XHTMLReader &reader);
+ static void restartParagraph(XHTMLReader &reader);
};
class XHTMLReader : public ZLXMLReader {
@@ -93,6 +94,7 @@ private:
void beginParagraph();
void endParagraph();
+ void restartParagraph();
bool addTextStyleEntry(const std::string tag, const std::string aClass);
void addTextStyleEntry(const ZLTextStyleEntry &entry);
diff --git a/src/org/geometerplus/fbreader/bookmodel/FBTextKind.java b/src/org/geometerplus/fbreader/bookmodel/FBTextKind.java
index d2194c59d..0584c589c 100644
--- a/src/org/geometerplus/fbreader/bookmodel/FBTextKind.java
+++ b/src/org/geometerplus/fbreader/bookmodel/FBTextKind.java
@@ -60,4 +60,6 @@ public interface FBTextKind {
byte H6 = 36;
byte EXTERNAL_HYPERLINK = 37;
//byte BOOK_HYPERLINK = 38;
+
+ byte XHTML_TAG_P = 51;
};
diff --git a/src/org/geometerplus/zlibrary/text/model/ZLTextMetrics.java b/src/org/geometerplus/zlibrary/text/model/ZLTextMetrics.java
index 009fea5cd..668f97597 100644
--- a/src/org/geometerplus/zlibrary/text/model/ZLTextMetrics.java
+++ b/src/org/geometerplus/zlibrary/text/model/ZLTextMetrics.java
@@ -22,16 +22,12 @@ package org.geometerplus.zlibrary.text.model;
public final class ZLTextMetrics {
public final int DPI;
public final int DefaultFontSize;
- public final int FontSize;
- public final int FontXHeight;
public final int FullWidth;
public final int FullHeight;
- public ZLTextMetrics(int dpi, int defaultFontSize, int fontSize, int fontXHeight, int fullWidth, int fullHeight) {
+ public ZLTextMetrics(int dpi, int defaultFontSize, int fullWidth, int fullHeight) {
DPI = dpi;
DefaultFontSize = defaultFontSize;
- FontSize = fontSize;
- FontXHeight = fontXHeight;
FullWidth = fullWidth;
FullHeight = fullHeight;
}
@@ -46,14 +42,14 @@ public final class ZLTextMetrics {
}
final ZLTextMetrics oo = (ZLTextMetrics)o;
return
- FontSize == oo.FontSize &&
- FontXHeight == oo.FontXHeight &&
+ DPI == oo.DPI &&
+ DefaultFontSize == oo.DefaultFontSize &&
FullWidth == oo.FullWidth &&
FullHeight == oo.FullHeight;
}
@Override
public int hashCode() {
- return FontSize + 13 * (FontXHeight + 13 * (FullHeight + 13 * FullWidth));
+ return DPI + 13 * (DefaultFontSize + 13 * (FullHeight + 13 * FullWidth));
}
}
diff --git a/src/org/geometerplus/zlibrary/text/model/ZLTextStyleEntry.java b/src/org/geometerplus/zlibrary/text/model/ZLTextStyleEntry.java
index 69a0a1467..f2fbd7d19 100644
--- a/src/org/geometerplus/zlibrary/text/model/ZLTextStyleEntry.java
+++ b/src/org/geometerplus/zlibrary/text/model/ZLTextStyleEntry.java
@@ -59,11 +59,11 @@ public abstract class ZLTextStyleEntry {
byte PERCENT = 4;
}
- private class Length {
+ public static class Length {
public final short Size;
public final byte Unit;
- Length(short size, byte unit) {
+ public Length(short size, byte unit) {
Size = size;
Unit = unit;
}
@@ -93,7 +93,7 @@ public abstract class ZLTextStyleEntry {
myLengths[featureId] = new Length(size, unit);
}
- private int fullSize(ZLTextMetrics metrics, int featureId) {
+ private static int fullSize(ZLTextMetrics metrics, int fontSize, int featureId) {
switch (featureId) {
default:
case Feature.LENGTH_LEFT_INDENT:
@@ -104,26 +104,31 @@ public abstract class ZLTextStyleEntry {
case Feature.LENGTH_SPACE_AFTER:
return metrics.FullHeight;
case Feature.LENGTH_FONT_SIZE:
- return metrics.FontSize;
+ return fontSize;
}
}
- public final int getLength(int featureId, ZLTextMetrics metrics) {
- switch (myLengths[featureId].Unit) {
+ public final int getLength(int featureId, ZLTextMetrics metrics, int baseFontSize) {
+ return compute(myLengths[featureId], metrics, baseFontSize, featureId);
+ }
+
+ public static int compute(Length length, ZLTextMetrics metrics, int baseFontSize, int featureId) {
+ switch (length.Unit) {
default:
case SizeUnit.PIXEL:
- return myLengths[featureId].Size * metrics.FontSize / metrics.DefaultFontSize;
+ return length.Size * baseFontSize / metrics.DefaultFontSize;
// we understand "point" as "1/2 point"
case SizeUnit.POINT:
- return myLengths[featureId].Size
- * metrics.DPI * metrics.FontSize
+ return length.Size
+ * metrics.DPI * baseFontSize
/ 72 / metrics.DefaultFontSize / 2;
case SizeUnit.EM_100:
- return (myLengths[featureId].Size * metrics.FontSize + 50) / 100;
+ return (length.Size * baseFontSize + 50) / 100;
case SizeUnit.EX_100:
- return (myLengths[featureId].Size * metrics.FontXHeight + 50) / 100;
+ // TODO 1.5 font size => height of X
+ return (length.Size * baseFontSize * 3 / 2 + 50) / 100;
case SizeUnit.PERCENT:
- return (myLengths[featureId].Size * fullSize(metrics, featureId) + 50) / 100;
+ return (length.Size * fullSize(metrics, baseFontSize, featureId) + 50) / 100;
}
}
diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextView.java b/src/org/geometerplus/zlibrary/text/view/ZLTextView.java
index b02f408a1..e027fead4 100644
--- a/src/org/geometerplus/zlibrary/text/view/ZLTextView.java
+++ b/src/org/geometerplus/zlibrary/text/view/ZLTextView.java
@@ -645,8 +645,10 @@ public abstract class ZLTextView extends ZLTextViewBase {
charsPerParagraph * 1.2f);
final int strHeight = getWordHeight() + getContext().getDescent();
- final int effectiveHeight = (int) (textHeight - (getTextStyle().getSpaceBefore(metrics())
- + getTextStyle().getSpaceAfter(metrics())) / charsPerParagraph);
+ final int effectiveHeight = (int)
+ (textHeight -
+ (getTextStyle().getSpaceBefore(metrics())
+ + getTextStyle().getSpaceAfter(metrics()) / 2) / charsPerParagraph);
final int linesPerPage = effectiveHeight / strHeight;
return charsPerLine * linesPerPage;
diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextViewBase.java b/src/org/geometerplus/zlibrary/text/view/ZLTextViewBase.java
index 33312a4ea..c71e59fc8 100644
--- a/src/org/geometerplus/zlibrary/text/view/ZLTextViewBase.java
+++ b/src/org/geometerplus/zlibrary/text/view/ZLTextViewBase.java
@@ -52,14 +52,9 @@ abstract class ZLTextViewBase extends ZLView {
// be returned from this method enen in multi-thread environment
ZLTextMetrics m = myMetrics;
if (m == null) {
- final ZLTextStyleCollection collection = getTextStyleCollection();
- final ZLTextBaseStyle base = collection.getBaseStyle();
m = new ZLTextMetrics(
ZLibrary.Instance().getDisplayDPI(),
- collection.getDefaultFontSize(),
- base.getFontSize(),
- // TODO: font X height
- base.getFontSize() * 15 / 10,
+ getTextStyleCollection().getDefaultFontSize(),
// TODO: screen area width
100,
// TODO: screen area height
@@ -156,12 +151,18 @@ abstract class ZLTextViewBase extends ZLView {
private void applyControl(ZLTextControlElement control) {
if (control.IsStart) {
- final ZLTextStyleDecoration decoration =
- getTextStyleCollection().getDecoration(control.Kind);
- if (control instanceof ZLTextHyperlinkControlElement) {
- setTextStyle(decoration.createDecoratedStyle(myTextStyle, ((ZLTextHyperlinkControlElement)control).Hyperlink));
+ final ZLTextNGStyleDescription description =
+ getTextStyleCollection().getDescription(control.Kind);
+ if (description != null) {
+ setTextStyle(new ZLTextNGStyle(myTextStyle, description));
} else {
- setTextStyle(decoration.createDecoratedStyle(myTextStyle));
+ final ZLTextStyleDecoration decoration =
+ getTextStyleCollection().getDecoration(control.Kind);
+ if (control instanceof ZLTextHyperlinkControlElement) {
+ setTextStyle(decoration.createDecoratedStyle(myTextStyle, ((ZLTextHyperlinkControlElement)control).Hyperlink));
+ } else {
+ setTextStyle(decoration.createDecoratedStyle(myTextStyle));
+ }
}
} else {
setTextStyle(myTextStyle.Parent);
diff --git a/src/org/geometerplus/zlibrary/text/view/style/SimpleCSSReader.java b/src/org/geometerplus/zlibrary/text/view/style/SimpleCSSReader.java
new file mode 100644
index 000000000..780252f2d
--- /dev/null
+++ b/src/org/geometerplus/zlibrary/text/view/style/SimpleCSSReader.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007-2014 Geometer Plus
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+package org.geometerplus.zlibrary.text.view.style;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.geometerplus.zlibrary.core.filesystem.ZLFile;
+
+class SimpleCSSReader {
+ private enum State {
+ EXPECT_SELECTOR,
+ EXPECT_OPEN_BRACKET,
+ EXPECT_NAME,
+ EXPECT_VALUE
+ }
+
+ private State myState;
+ private Map myDescriptionMap;
+ private Map myCurrentMap;
+ private String mySelector;
+ private String myName;
+
+ Map read(ZLFile file) {
+ myDescriptionMap = new LinkedHashMap();
+ myState = State.EXPECT_SELECTOR;
+
+ InputStream stream = null;
+ try {
+ stream = file.getInputStream();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ for (String token : smartSplit(line)) {
+ processToken(token);
+ }
+ }
+ } catch (IOException e) {
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ return myDescriptionMap;
+ }
+
+ private void processToken(String token) {
+ switch (myState) {
+ case EXPECT_SELECTOR:
+ mySelector = token;
+ myState = State.EXPECT_OPEN_BRACKET;
+ break;
+ case EXPECT_OPEN_BRACKET:
+ if ("{".equals(token)) {
+ myCurrentMap = new HashMap();
+ myState = State.EXPECT_NAME;
+ }
+ break;
+ case EXPECT_NAME:
+ if ("}".equals(token)) {
+ if (mySelector != null) {
+ try {
+ myDescriptionMap.put(
+ Integer.valueOf(myCurrentMap.get("fbreader-id")),
+ new ZLTextNGStyleDescription(mySelector, myCurrentMap)
+ );
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ myState = State.EXPECT_SELECTOR;
+ } else {
+ myName = token;
+ myState = State.EXPECT_VALUE;
+ }
+ break;
+ case EXPECT_VALUE:
+ if (myCurrentMap != null && myName != null) {
+ myCurrentMap.put(myName, token);
+ }
+ myState = State.EXPECT_NAME;
+ break;
+ }
+ }
+
+ private static List smartSplit(String line) {
+ final List tokens = new LinkedList();
+ final Matcher m = Pattern.compile("([^\"\\s:;]+|\".+?\")").matcher(line);
+ while (m.find()) {
+ tokens.add(m.group(1).replace("\"", ""));
+ }
+ return tokens;
+ }
+}
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextBaseStyle.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextBaseStyle.java
index 62726dd37..a62936441 100644
--- a/src/org/geometerplus/zlibrary/text/view/style/ZLTextBaseStyle.java
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextBaseStyle.java
@@ -37,6 +37,8 @@ public class ZLTextBaseStyle extends ZLTextStyle {
public final ZLBooleanOption UseCSSTextAlignmentOption =
new ZLBooleanOption("Style", "css:textAlignment", true);
+ public final ZLBooleanOption UseCSSMarginsOption =
+ new ZLBooleanOption("Style", "css:margins", true);
public final ZLBooleanOption UseCSSFontSizeOption =
new ZLBooleanOption("Style", "css:fontSize", true);
public final ZLBooleanOption UseCSSFontFamilyOption =
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextDecoratedStyle.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextDecoratedStyle.java
index b12214d03..7e231d366 100644
--- a/src/org/geometerplus/zlibrary/text/view/style/ZLTextDecoratedStyle.java
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextDecoratedStyle.java
@@ -65,8 +65,8 @@ public abstract class ZLTextDecoratedStyle extends ZLTextStyle {
private void initMetricsCache(ZLTextMetrics metrics) {
myMetrics = metrics;
myFontSize = getFontSizeInternal(metrics);
- mySpaceBefore = getSpaceBeforeInternal(metrics);
- mySpaceAfter = getSpaceAfterInternal(metrics);
+ mySpaceBefore = getSpaceBeforeInternal(metrics, myFontSize);
+ mySpaceAfter = getSpaceAfterInternal(metrics, myFontSize);
}
@Override
@@ -94,7 +94,7 @@ public abstract class ZLTextDecoratedStyle extends ZLTextStyle {
}
return mySpaceBefore;
}
- protected abstract int getSpaceBeforeInternal(ZLTextMetrics metrics);
+ protected abstract int getSpaceBeforeInternal(ZLTextMetrics metrics, int fontSize);
@Override
public final int getSpaceAfter(ZLTextMetrics metrics) {
@@ -103,7 +103,7 @@ public abstract class ZLTextDecoratedStyle extends ZLTextStyle {
}
return mySpaceAfter;
}
- protected abstract int getSpaceAfterInternal(ZLTextMetrics metrics);
+ protected abstract int getSpaceAfterInternal(ZLTextMetrics metrics, int fontSize);
@Override
public final boolean isItalic() {
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextExplicitlyDecoratedStyle.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextExplicitlyDecoratedStyle.java
index a63f8ae64..0b0b0dc89 100644
--- a/src/org/geometerplus/zlibrary/text/view/style/ZLTextExplicitlyDecoratedStyle.java
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextExplicitlyDecoratedStyle.java
@@ -69,19 +69,22 @@ public class ZLTextExplicitlyDecoratedStyle extends ZLTextDecoratedStyle impleme
return Parent.getFontSize(metrics);
}
+ // Yes, Parent.Parent, not Parent (parent = current tag pre-defined size,
+ // we want to override it)
+ final int baseFontSize = Parent.Parent.getFontSize(metrics);
if (myEntry.isFeatureSupported(FONT_STYLE_MODIFIER)) {
if (myEntry.getFontModifier(FONT_MODIFIER_INHERIT) == ZLBoolean3.B3_TRUE) {
- return Parent.Parent.getFontSize(metrics);
+ return baseFontSize;
}
if (myEntry.getFontModifier(FONT_MODIFIER_LARGER) == ZLBoolean3.B3_TRUE) {
- return Parent.Parent.getFontSize(metrics) * 120 / 100;
+ return baseFontSize * 120 / 100;
}
if (myEntry.getFontModifier(FONT_MODIFIER_SMALLER) == ZLBoolean3.B3_TRUE) {
- return Parent.Parent.getFontSize(metrics) * 100 / 120;
+ return baseFontSize * 100 / 120;
}
}
if (myEntry.isFeatureSupported(LENGTH_FONT_SIZE)) {
- return myEntry.getLength(LENGTH_FONT_SIZE, metrics);
+ return myEntry.getLength(LENGTH_FONT_SIZE, metrics, baseFontSize);
}
return Parent.getFontSize(metrics);
}
@@ -153,26 +156,26 @@ public class ZLTextExplicitlyDecoratedStyle extends ZLTextDecoratedStyle impleme
return Parent.getVerticalShift();
}
@Override
- protected int getSpaceBeforeInternal(ZLTextMetrics metrics) {
- if (myEntry instanceof ZLTextCSSStyleEntry && !BaseStyle.UseCSSFontFamilyOption.getValue()) {
+ protected int getSpaceBeforeInternal(ZLTextMetrics metrics, int fontSize) {
+ if (myEntry instanceof ZLTextCSSStyleEntry && !BaseStyle.UseCSSMarginsOption.getValue()) {
return Parent.getSpaceBefore(metrics);
}
if (!myEntry.isFeatureSupported(LENGTH_SPACE_BEFORE)) {
return Parent.getSpaceBefore(metrics);
}
- return myEntry.getLength(LENGTH_SPACE_BEFORE, metrics);
+ return myEntry.getLength(LENGTH_SPACE_BEFORE, metrics, fontSize);
}
@Override
- protected int getSpaceAfterInternal(ZLTextMetrics metrics) {
- if (myEntry instanceof ZLTextCSSStyleEntry && !BaseStyle.UseCSSFontFamilyOption.getValue()) {
+ protected int getSpaceAfterInternal(ZLTextMetrics metrics, int fontSize) {
+ if (myEntry instanceof ZLTextCSSStyleEntry && !BaseStyle.UseCSSMarginsOption.getValue()) {
return Parent.getSpaceAfter(metrics);
}
if (!myEntry.isFeatureSupported(LENGTH_SPACE_AFTER)) {
return Parent.getSpaceAfter(metrics);
}
- return myEntry.getLength(LENGTH_SPACE_AFTER, metrics);
+ return myEntry.getLength(LENGTH_SPACE_AFTER, metrics, fontSize);
}
public byte getAlignment() {
if (myEntry instanceof ZLTextCSSStyleEntry && !BaseStyle.UseCSSTextAlignmentOption.getValue()) {
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextFullyDecoratedStyle.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextFullyDecoratedStyle.java
index b3926855e..56457ec79 100644
--- a/src/org/geometerplus/zlibrary/text/view/style/ZLTextFullyDecoratedStyle.java
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextFullyDecoratedStyle.java
@@ -54,12 +54,12 @@ public class ZLTextFullyDecoratedStyle extends ZLTextPartiallyDecoratedStyle {
}
@Override
- protected int getSpaceBeforeInternal(ZLTextMetrics metrics) {
+ protected int getSpaceBeforeInternal(ZLTextMetrics metrics, int fontSize) {
return myFullDecoration.SpaceBeforeOption.getValue();
}
@Override
- protected int getSpaceAfterInternal(ZLTextMetrics metrics) {
+ protected int getSpaceAfterInternal(ZLTextMetrics metrics, int fontSize) {
return myFullDecoration.SpaceAfterOption.getValue();
}
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextNGStyle.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextNGStyle.java
new file mode 100644
index 000000000..bf09c0478
--- /dev/null
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextNGStyle.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007-2014 Geometer Plus
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+package org.geometerplus.zlibrary.text.view.style;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.geometerplus.zlibrary.core.fonts.FontEntry;
+import org.geometerplus.zlibrary.core.util.ZLBoolean3;
+import org.geometerplus.zlibrary.text.model.ZLTextAlignmentType;
+import org.geometerplus.zlibrary.text.model.ZLTextMetrics;
+import org.geometerplus.zlibrary.text.view.ZLTextStyle;
+
+public class ZLTextNGStyle extends ZLTextDecoratedStyle {
+ private final ZLTextNGStyleDescription myDescription;
+
+ public ZLTextNGStyle(ZLTextStyle parent, ZLTextNGStyleDescription description) {
+ super(parent, parent.Hyperlink);
+ myDescription = description;
+ }
+
+ @Override
+ protected List getFontEntriesInternal() {
+ final List parentEntries = Parent.getFontEntries();
+ final String decoratedValue = myDescription.FontFamilyOption.getValue();
+ if ("".equals(decoratedValue)) {
+ return parentEntries;
+ }
+ final FontEntry e = FontEntry.systemEntry(decoratedValue);
+ if (parentEntries.size() > 0 && e.equals(parentEntries.get(0))) {
+ return parentEntries;
+ }
+ final List entries = new ArrayList(parentEntries.size() + 1);
+ entries.add(e);
+ entries.addAll(parentEntries);
+ return entries;
+ }
+
+ @Override
+ protected int getFontSizeInternal(ZLTextMetrics metrics) {
+ return myDescription.getFontSize(metrics, Parent.getFontSize(metrics));
+ }
+
+ @Override
+ protected boolean isBoldInternal() {
+ switch (myDescription.isBold()) {
+ case B3_TRUE:
+ return true;
+ case B3_FALSE:
+ return false;
+ default:
+ return Parent.isBold();
+ }
+ }
+ @Override
+ protected boolean isItalicInternal() {
+ switch (myDescription.isItalic()) {
+ case B3_TRUE:
+ return true;
+ case B3_FALSE:
+ return false;
+ default:
+ return Parent.isItalic();
+ }
+ }
+ @Override
+ protected boolean isUnderlineInternal() {
+ switch (myDescription.isUnderlined()) {
+ case B3_TRUE:
+ return true;
+ case B3_FALSE:
+ return false;
+ default:
+ return Parent.isUnderline();
+ }
+ }
+ @Override
+ protected boolean isStrikeThroughInternal() {
+ switch (myDescription.isStrikedThrough()) {
+ case B3_TRUE:
+ return true;
+ case B3_FALSE:
+ return false;
+ default:
+ return Parent.isStrikeThrough();
+ }
+ }
+
+ public int getLeftIndent() {
+ // TODO: implement
+ return Parent.getLeftIndent();
+ }
+ public int getRightIndent() {
+ // TODO: implement
+ return Parent.getRightIndent();
+ }
+ public int getFirstLineIndentDelta() {
+ // TODO: implement
+ return Parent.getFirstLineIndentDelta();
+ }
+ public int getLineSpacePercent() {
+ // TODO: implement
+ return Parent.getLineSpacePercent();
+ }
+ @Override
+ protected int getVerticalShiftInternal() {
+ // TODO: implement
+ return Parent.getVerticalShift();
+ }
+ @Override
+ protected int getSpaceBeforeInternal(ZLTextMetrics metrics, int fontSize) {
+ return myDescription.getSpaceBefore(metrics, Parent.getSpaceBefore(metrics), fontSize);
+ }
+ @Override
+ protected int getSpaceAfterInternal(ZLTextMetrics metrics, int fontSize) {
+ return myDescription.getSpaceAfter(metrics, Parent.getSpaceAfter(metrics), fontSize);
+ }
+
+ @Override
+ public byte getAlignment() {
+ final byte defined = myDescription.getAlignment();
+ if (defined != ZLTextAlignmentType.ALIGN_UNDEFINED) {
+ return defined;
+ }
+ return Parent.getAlignment();
+ }
+
+ @Override
+ public boolean allowHyphenations() {
+ switch (myDescription.allowHyphenations()) {
+ case B3_TRUE:
+ return true;
+ case B3_FALSE:
+ return false;
+ default:
+ return Parent.allowHyphenations();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ZLTextNGStyle[" + myDescription.Name + "]";
+ }
+}
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextNGStyleDescription.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextNGStyleDescription.java
new file mode 100644
index 000000000..0c9dcca76
--- /dev/null
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextNGStyleDescription.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2007-2014 Geometer Plus
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+package org.geometerplus.zlibrary.text.view.style;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import org.geometerplus.zlibrary.core.options.ZLStringOption;
+import org.geometerplus.zlibrary.core.util.ZLBoolean3;
+import org.geometerplus.zlibrary.text.model.*;
+
+public class ZLTextNGStyleDescription {
+ public final String Name;
+
+ public final ZLStringOption FontFamilyOption;
+ public final ZLStringOption FontSizeOption;
+ public final ZLStringOption FontWeightOption;
+ public final ZLStringOption FontStyleOption;
+ public final ZLStringOption HyphenationOption;
+ public final ZLStringOption MarginTopOption;
+ public final ZLStringOption MarginBottomOption;
+ public final ZLStringOption AlignmentOption;
+
+ private static ZLStringOption createOption(String selector, String name, Map valueMap) {
+ return new ZLStringOption("Style", selector + "::" + name, valueMap.get(name));
+ }
+
+ ZLTextNGStyleDescription(String selector, Map valueMap) {
+ Name = valueMap.get("fbreader-name");
+
+ FontFamilyOption = createOption(selector, "font-family", valueMap);
+ FontSizeOption = createOption(selector, "font-size", valueMap);
+ FontWeightOption = createOption(selector, "font-weight", valueMap);
+ FontStyleOption = createOption(selector, "font-style", valueMap);
+ HyphenationOption = createOption(selector, "hyphens", valueMap);
+ MarginTopOption = createOption(selector, "margin-top", valueMap);
+ MarginBottomOption = createOption(selector, "margin-bottom", valueMap);
+ AlignmentOption = createOption(selector, "text-align", valueMap);
+ }
+
+ int getFontSize(ZLTextMetrics metrics, int baseFontSize) {
+ final ZLTextStyleEntry.Length length = parseLength(FontSizeOption.getValue());
+ if (length == null) {
+ return baseFontSize;
+ }
+ return ZLTextStyleEntry.compute(
+ length, metrics, baseFontSize, ZLTextStyleEntry.Feature.LENGTH_FONT_SIZE
+ );
+ }
+
+ int getSpaceBefore(ZLTextMetrics metrics, int base, int fontSize) {
+ final ZLTextStyleEntry.Length length = parseLength(MarginTopOption.getValue());
+ if (length == null) {
+ return base;
+ }
+ return ZLTextStyleEntry.compute(
+ length, metrics, fontSize, ZLTextStyleEntry.Feature.LENGTH_SPACE_BEFORE
+ );
+ }
+
+ int getSpaceAfter(ZLTextMetrics metrics, int base, int fontSize) {
+ final ZLTextStyleEntry.Length length = parseLength(MarginBottomOption.getValue());
+ if (length == null) {
+ return base;
+ }
+ return ZLTextStyleEntry.compute(
+ length, metrics, fontSize, ZLTextStyleEntry.Feature.LENGTH_SPACE_AFTER
+ );
+ }
+
+ ZLBoolean3 isBold() {
+ final String fontWeight = FontWeightOption.getValue();
+ if ("bold".equals(fontWeight)) {
+ return ZLBoolean3.B3_TRUE;
+ } else if ("normal".equals(fontWeight)) {
+ return ZLBoolean3.B3_FALSE;
+ } else {
+ return ZLBoolean3.B3_UNDEFINED;
+ }
+ }
+ ZLBoolean3 isItalic() {
+ final String fontStyle = FontStyleOption.getValue();
+ if ("italic".equals(fontStyle) || "oblique".equals(fontStyle)) {
+ return ZLBoolean3.B3_TRUE;
+ } else if ("normal".equals(fontStyle)) {
+ return ZLBoolean3.B3_FALSE;
+ } else {
+ return ZLBoolean3.B3_UNDEFINED;
+ }
+ }
+ ZLBoolean3 isUnderlined() {
+ return ZLBoolean3.B3_UNDEFINED;
+ }
+ ZLBoolean3 isStrikedThrough() {
+ return ZLBoolean3.B3_UNDEFINED;
+ }
+
+ byte getAlignment() {
+ final String alignment = AlignmentOption.getValue();
+ if (alignment.length() == 0) {
+ return ZLTextAlignmentType.ALIGN_UNDEFINED;
+ } else if ("center".equals(alignment)) {
+ return ZLTextAlignmentType.ALIGN_CENTER;
+ } else if ("left".equals(alignment)) {
+ return ZLTextAlignmentType.ALIGN_LEFT;
+ } else if ("right".equals(alignment)) {
+ return ZLTextAlignmentType.ALIGN_RIGHT;
+ } else if ("justify".equals(alignment)) {
+ return ZLTextAlignmentType.ALIGN_JUSTIFY;
+ } else {
+ return ZLTextAlignmentType.ALIGN_UNDEFINED;
+ }
+ }
+
+ ZLBoolean3 allowHyphenations() {
+ final String hyphen = HyphenationOption.getValue();
+ if ("auto".equals(hyphen)) {
+ return ZLBoolean3.B3_TRUE;
+ } else if ("none".equals(hyphen)) {
+ return ZLBoolean3.B3_FALSE;
+ } else {
+ return ZLBoolean3.B3_UNDEFINED;
+ }
+ }
+
+ private static final Map ourCache = new HashMap();
+ private static final Object ourNullObject = new Object();
+ private static ZLTextStyleEntry.Length parseLength(String value) {
+ if (value.length() == 0) {
+ return null;
+ }
+
+ final Object cached = ourCache.get(value);
+ if (cached != null) {
+ return cached == ourNullObject ? null : (ZLTextStyleEntry.Length)cached;
+ }
+
+ ZLTextStyleEntry.Length length = null;
+ try {
+ if (value.endsWith("%")) {
+ length = new ZLTextStyleEntry.Length(
+ Short.valueOf(value.substring(0, value.length() - 1)),
+ ZLTextStyleEntry.SizeUnit.PERCENT
+ );
+ } else if (value.endsWith("em")) {
+ length = new ZLTextStyleEntry.Length(
+ (short)(100 * Double.valueOf(value.substring(0, value.length() - 2))),
+ ZLTextStyleEntry.SizeUnit.EM_100
+ );
+ } else if (value.endsWith("ex")) {
+ length = new ZLTextStyleEntry.Length(
+ (short)(100 * Double.valueOf(value.substring(0, value.length() - 2))),
+ ZLTextStyleEntry.SizeUnit.EX_100
+ );
+ } else if (value.endsWith("px")) {
+ length = new ZLTextStyleEntry.Length(
+ Short.valueOf(value.substring(0, value.length() - 2)),
+ ZLTextStyleEntry.SizeUnit.PIXEL
+ );
+ } else if (value.endsWith("pt")) {
+ length = new ZLTextStyleEntry.Length(
+ Short.valueOf(value.substring(0, value.length() - 2)),
+ ZLTextStyleEntry.SizeUnit.POINT
+ );
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ ourCache.put(value, length != null ? length : ourNullObject);
+ return length;
+ }
+}
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextPartiallyDecoratedStyle.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextPartiallyDecoratedStyle.java
index 25d2ad536..a170f776c 100644
--- a/src/org/geometerplus/zlibrary/text/view/style/ZLTextPartiallyDecoratedStyle.java
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextPartiallyDecoratedStyle.java
@@ -131,12 +131,12 @@ class ZLTextPartiallyDecoratedStyle extends ZLTextDecoratedStyle {
}
@Override
- protected int getSpaceBeforeInternal(ZLTextMetrics metrics) {
+ protected int getSpaceBeforeInternal(ZLTextMetrics metrics, int fontSize) {
return Parent.getSpaceBefore(metrics);
}
@Override
- protected int getSpaceAfterInternal(ZLTextMetrics metrics) {
+ protected int getSpaceAfterInternal(ZLTextMetrics metrics, int fontSize) {
return Parent.getSpaceAfter(metrics);
}
diff --git a/src/org/geometerplus/zlibrary/text/view/style/ZLTextStyleCollection.java b/src/org/geometerplus/zlibrary/text/view/style/ZLTextStyleCollection.java
index f510ba8fc..b319ae5f8 100644
--- a/src/org/geometerplus/zlibrary/text/view/style/ZLTextStyleCollection.java
+++ b/src/org/geometerplus/zlibrary/text/view/style/ZLTextStyleCollection.java
@@ -19,6 +19,8 @@
package org.geometerplus.zlibrary.text.view.style;
+import java.util.Map;
+
import org.geometerplus.zlibrary.core.filesystem.ZLResourceFile;
import org.geometerplus.zlibrary.core.library.ZLibrary;
import org.geometerplus.zlibrary.core.util.ZLBoolean3;
@@ -29,10 +31,16 @@ public class ZLTextStyleCollection {
public final String Screen;
private int myDefaultFontSize;
private ZLTextBaseStyle myBaseStyle;
+ private final ZLTextNGStyleDescription[] myDescriptionMap = new ZLTextNGStyleDescription[256];
private final ZLTextStyleDecoration[] myDecorationMap = new ZLTextStyleDecoration[256];
public ZLTextStyleCollection(String screen) {
Screen = screen;
+ final Map descriptions =
+ new SimpleCSSReader().read(ZLResourceFile.createResourceFile("default/styles.css"));
+ for (Map.Entry entry : descriptions.entrySet()) {
+ myDescriptionMap[entry.getKey() & 0xFF] = entry.getValue();
+ }
new TextStyleReader().readQuietly(ZLResourceFile.createResourceFile("default/styles.xml"));
}
@@ -44,6 +52,10 @@ public class ZLTextStyleCollection {
return myBaseStyle;
}
+ public ZLTextNGStyleDescription getDescription(byte kind) {
+ return myDescriptionMap[kind & 0xFF];
+ }
+
public ZLTextStyleDecoration getDecoration(byte kind) {
return myDecorationMap[kind & 0xFF];
}