1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-06 03:50:19 +02:00

embedded fonts processing (in progress)

This commit is contained in:
Nikolay Pultsin 2014-03-30 11:20:27 +03:00
parent 06e46d4c33
commit 59639078ea
12 changed files with 209 additions and 84 deletions

View file

@ -105,6 +105,7 @@ LOCAL_SRC_FILES := \
NativeFormats/fbreader/src/formats/css/StringInputStream.cpp \
NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp \
NativeFormats/fbreader/src/formats/css/StyleSheetTable.cpp \
NativeFormats/fbreader/src/formats/css/StyleSheetUtil.cpp \
NativeFormats/fbreader/src/formats/html/HtmlBookReader.cpp \
NativeFormats/fbreader/src/formats/html/HtmlDescriptionReader.cpp \
NativeFormats/fbreader/src/formats/html/HtmlEntityCollection.cpp \

View file

@ -39,6 +39,21 @@ void FontEntry::addFile(const std::string &weight, const std::string &style, con
}
}
void FontEntry::merge(const FontEntry &fontEntry) {
if (!fontEntry.Normal.isNull()) {
Normal = fontEntry.Normal;
}
if (!fontEntry.Bold.isNull()) {
Bold = fontEntry.Bold;
}
if (!fontEntry.Italic.isNull()) {
Italic = fontEntry.Italic;
}
if (!fontEntry.BoldItalic.isNull()) {
BoldItalic = fontEntry.BoldItalic;
}
}
static bool compareStringPtrs(shared_ptr<std::string> str0, shared_ptr<std::string> str1) {
return str0.isNull() ? str1.isNull() : (!str1.isNull() && *str0 == *str1);
}
@ -55,16 +70,55 @@ bool FontEntry::operator != (const FontEntry &other) const {
return !operator ==(other);
}
bool FontMap::operator == (const FontMap &other) const {
return myMap == other.myMap;
}
bool FontMap::operator != (const FontMap &other) const {
return !operator ==(other);
}
void FontMap::appendFontFace(const std::string &family, const std::string &weight, const std::string &style, const std::string &path) {
void FontMap::append(const std::string &family, const std::string &weight, const std::string &style, const std::string &path) {
const ZLFile fontFile(path);
myMap[family].addFile(weight, style, fontFile.path());
ZLLogger::Instance().println("FONT", family + " => " + fontFile.path());
shared_ptr<FontEntry> entry = myMap[family];
if (entry.isNull()) {
entry = new FontEntry();
myMap[family] = entry;
}
entry->addFile(weight, style, fontFile.path());
ZLLogger::Instance().println("FONT", family + "," + weight + "," + style + " => " + fontFile.path());
}
void FontMap::merge(const FontMap &fontMap) {
for (std::map<std::string,shared_ptr<FontEntry> >::const_iterator it = fontMap.myMap.begin(); it != fontMap.myMap.end(); ++it) {
if (!it->second.isNull()) {
shared_ptr<FontEntry> entry = myMap[it->first];
if (entry.isNull()) {
entry = new FontEntry();
myMap[it->first] = entry;
}
entry->merge(*it->second);
}
}
}
shared_ptr<FontEntry> FontMap::get(const std::string &family) {
return myMap[family];
}
std::string FontMap::put(const std::string &family, shared_ptr<FontEntry> entry) {
shared_ptr<FontEntry> existing = myMap[family];
if (existing.isNull() || *existing == *entry) {
myMap[family] = entry;
return family;
}
for (std::map<std::string,shared_ptr<FontEntry> >::const_iterator it = myMap.begin(); it != myMap.end(); ++it) {
if (*it->second == *entry) {
return it->first;
}
}
for (int i = 1; i < 1000; ++i) {
std::string indexed = family + "#";
ZLStringUtil::appendNumber(indexed, i);
if (myMap[indexed].isNull()) {
myMap[indexed] = entry;
return indexed;
}
}
return std::string();
}

View file

@ -29,6 +29,7 @@ class FontEntry {
public:
void addFile(const std::string &weight, const std::string &style, const std::string &filePath);
void merge(const FontEntry &fontEntry);
bool operator == (const FontEntry &other) const;
bool operator != (const FontEntry &other) const;
@ -43,13 +44,13 @@ public:
class FontMap {
public:
bool operator == (const FontMap &other) const;
bool operator != (const FontMap &other) const;
void appendFontFace(const std::string &family, const std::string &weight, const std::string &style, const std::string &path);
void append(const std::string &family, const std::string &weight, const std::string &style, const std::string &path);
void merge(const FontMap &fontMap);
std::string put(const std::string &family, shared_ptr<FontEntry> entry);
shared_ptr<FontEntry> get(const std::string &family);
private:
std::map<std::string,FontEntry> myMap;
std::map<std::string,shared_ptr<FontEntry> > myMap;
};
#endif /* __FONTMAP_H__ */

View file

@ -26,6 +26,7 @@
#include <ZLLogger.h>
#include "StyleSheetParser.h"
#include "StyleSheetUtil.h"
#include "StringInputStream.h"
#include "CSSInputStream.h"
#include "../util/MiscUtil.h"
@ -125,11 +126,9 @@ std::string StyleSheetParser::url2FullPath(const std::string &url) const {
ZLStringUtil::stringEndsWith(path, ")")) {
path = path.substr(4, path.size() - 5);
}
if (path.size() > 2 && path[0] == path[path.size() - 1]) {
if (path[0] == '\'' || path[0] == '"') {
if (path.size() > 1 && (path[0] == '"' || path[0] == '\'') && path[0] == path[path.size() - 1]) {
path = path.substr(1, path.size() - 2);
}
}
return myPathPrefix + MiscUtil::decodeHtmlURL(path);
}
@ -221,9 +220,13 @@ void StyleSheetParser::processWord(const std::string &word) {
myMap[myAttributeName].clear();
break;
case ATTRIBUTE_VALUE:
myMap[myAttributeName] = word;
{
std::string stripped = word;
ZLStringUtil::stripWhiteSpaces(stripped);
myMap[myAttributeName] = stripped;
break;
}
}
}
StyleSheetSingleStyleParser::StyleSheetSingleStyleParser(const std::string &pathPrefix) : StyleSheetParser(pathPrefix) {
@ -237,7 +240,7 @@ shared_ptr<ZLTextStyleEntry> StyleSheetSingleStyleParser::parseSingleEntry(const
return control;
}
StyleSheetMultiStyleParser::StyleSheetMultiStyleParser(const std::string &pathPrefix, FontMap &fontMap) : StyleSheetParser(pathPrefix), myFontMap(fontMap) {
StyleSheetMultiStyleParser::StyleSheetMultiStyleParser(const std::string &pathPrefix, shared_ptr<FontMap> fontMap) : StyleSheetParser(pathPrefix), myFontMap(fontMap.isNull() ? new FontMap() : fontMap) {
}
void StyleSheetMultiStyleParser::storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map) {
@ -279,11 +282,13 @@ static std::string value(const StyleSheetTable::AttributeMap &map, const std::st
void StyleSheetMultiStyleParser::processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &attributes) {
ZLLogger::Instance().registerClass("FONT");
if (name == "@font-face") {
const std::string family = value(attributes, "font-family");
std::string family = value(attributes, "font-family");
if (family.empty()) {
ZLLogger::Instance().println("FONT", "Font family not specified in @font-face entry");
return;
}
family = StyleSheetUtil::strip(family);
const StyleSheetTable::AttributeMap::const_iterator it = attributes.find("src");
std::string path;
if (it != attributes.end()) {
@ -301,7 +306,8 @@ void StyleSheetMultiStyleParser::processAtRule(const std::string &name, const St
ZLLogger::Instance().println("FONT", "Source not specified for " + family);
return;
}
myFontMap.appendFontFace(
myFontMap->append(
family,
value(attributes, "font-weight"),
value(attributes, "font-style"),
@ -310,14 +316,14 @@ void StyleSheetMultiStyleParser::processAtRule(const std::string &name, const St
}
}
StyleSheetTableParser::StyleSheetTableParser(const std::string &pathPrefix, StyleSheetTable &styleTable, FontMap &fontMap) : StyleSheetMultiStyleParser(pathPrefix, fontMap), myStyleTable(styleTable) {
StyleSheetTableParser::StyleSheetTableParser(const std::string &pathPrefix, StyleSheetTable &styleTable, shared_ptr<FontMap> fontMap) : StyleSheetMultiStyleParser(pathPrefix, fontMap), myStyleTable(styleTable) {
}
void StyleSheetTableParser::store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) {
myStyleTable.addMap(tag, aClass, map);
}
StyleSheetParserWithCache::StyleSheetParserWithCache(const ZLFile &file, const std::string &pathPrefix, FontMap &fontMap, shared_ptr<EncryptionMap> encryptionMap) : StyleSheetMultiStyleParser(pathPrefix, fontMap), myEncryptionMap(encryptionMap) {
StyleSheetParserWithCache::StyleSheetParserWithCache(const ZLFile &file, const std::string &pathPrefix, shared_ptr<FontMap> fontMap, shared_ptr<EncryptionMap> encryptionMap) : StyleSheetMultiStyleParser(pathPrefix, fontMap), myEncryptionMap(encryptionMap) {
myProcessedFiles.insert(file.path());
}
@ -344,9 +350,10 @@ void StyleSheetParserWithCache::importCSS(const std::string &path) {
myProcessedFiles.insert(fileToImport.path());
}
void StyleSheetParserWithCache::applyToTable(StyleSheetTable &table) const {
void StyleSheetParserWithCache::applyToTables(StyleSheetTable &table, FontMap &fontMap) const {
for (std::list<shared_ptr<Entry> >::const_iterator it = myEntries.begin(); it != myEntries.end(); ++it) {
const Entry &entry = **it;
table.addMap(entry.Tag, entry.Class, entry.Map);
}
fontMap.merge(*myFontMap);
}

View file

@ -86,7 +86,7 @@ public:
class StyleSheetMultiStyleParser : public StyleSheetParser {
protected:
StyleSheetMultiStyleParser(const std::string &pathPrefix, FontMap &map);
StyleSheetMultiStyleParser(const std::string &pathPrefix, shared_ptr<FontMap> myFontMap);
protected:
virtual void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) = 0;
@ -96,13 +96,13 @@ private:
void processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map);
protected:
FontMap &myFontMap;
shared_ptr<FontMap> myFontMap;
};
class StyleSheetTableParser : public StyleSheetMultiStyleParser {
public:
StyleSheetTableParser(const std::string &pathPrexix, StyleSheetTable &styleTable, FontMap &fontMap);
StyleSheetTableParser(const std::string &pathPrexix, StyleSheetTable &styleTable, shared_ptr<FontMap> fontMap);
private:
void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map);
@ -123,8 +123,8 @@ private:
};
public:
StyleSheetParserWithCache(const ZLFile &file, const std::string &pathPrefix, FontMap &fontMap, shared_ptr<EncryptionMap> encryptionMap);
void applyToTable(StyleSheetTable &table) const;
StyleSheetParserWithCache(const ZLFile &file, const std::string &pathPrefix, shared_ptr<FontMap> fontMap, shared_ptr<EncryptionMap> encryptionMap);
void applyToTables(StyleSheetTable &table, FontMap &fontMap) const;
private:
void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map);

View file

@ -22,6 +22,7 @@
#include <ZLStringUtil.h>
#include "StyleSheetTable.h"
#include "StyleSheetUtil.h"
bool StyleSheetTable::isEmpty() const {
return myControlMap.empty() && myPageBreakBeforeMap.empty() && myPageBreakAfterMap.empty();
@ -138,53 +139,6 @@ const std::string &StyleSheetTable::value(const AttributeMap &map, const std::st
return emptyString;
}
static std::string strip(const std::string &data) {
std::string res = data;
ZLStringUtil::stripWhiteSpaces(res);
if (res.size() > 1 && (res[0] == '"' || res[0] == '\'') && res[0] == res[res.size() - 1]) {
return res.substr(1, res.size() - 2);
} else {
return res;
}
}
static std::vector<std::string> splitCommaSeparatedList(const std::string &data) {
std::vector<std::string> split;
enum {
S_QUOTED,
D_QUOTED,
NORMAL
} state = NORMAL;
std::size_t start = 0;
for (std::size_t i = 0; i < data.size(); ++i) {
const char ch = data[i];
switch (state) {
case NORMAL:
if (ch == ',') {
if (i > start) {
split.push_back(strip(data.substr(start, i - start)));
}
start = i + 1;
}
break;
case S_QUOTED:
if (ch == '\'') {
state = NORMAL;
}
break;
case D_QUOTED:
if (ch == '"') {
state = NORMAL;
}
break;
}
}
return split;
}
shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &styles) {
shared_ptr<ZLTextStyleEntry> entry = new ZLTextStyleEntry(ZLTextStyleEntry::STYLE_CSS_ENTRY);
@ -240,7 +194,7 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &
const std::string &fontFamily = value(styles, "font-family");
if (!fontFamily.empty()) {
std::vector<std::string> families = splitCommaSeparatedList(fontFamily);
std::vector<std::string> families = StyleSheetUtil::splitCommaSeparatedList(fontFamily);
// TODO: use all families
if (!families.empty()) {
entry->setFontFamily(families[0]);

View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2004-2014 Geometer Plus <contact@geometerplus.com>
*
* 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.
*/
#include <ZLStringUtil.h>
#include "StyleSheetUtil.h"
std::string StyleSheetUtil::strip(const std::string &data) {
std::string res = data;
ZLStringUtil::stripWhiteSpaces(res);
if (res.size() > 1 && (res[0] == '"' || res[0] == '\'') && res[0] == res[res.size() - 1]) {
return res.substr(1, res.size() - 2);
} else {
return res;
}
}
std::vector<std::string> StyleSheetUtil::splitCommaSeparatedList(const std::string &data) {
std::vector<std::string> split;
enum {
S_QUOTED,
D_QUOTED,
NORMAL
} state = NORMAL;
std::size_t start = 0;
for (std::size_t i = 0; i < data.size(); ++i) {
const char ch = data[i];
switch (state) {
case NORMAL:
if (ch == ',') {
if (i > start) {
split.push_back(strip(data.substr(start, i - start)));
}
start = i + 1;
}
break;
case S_QUOTED:
if (ch == '\'') {
state = NORMAL;
}
break;
case D_QUOTED:
if (ch == '"') {
state = NORMAL;
}
break;
}
}
return split;
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2004-2014 Geometer Plus <contact@geometerplus.com>
*
* 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.
*/
#ifndef __STYLESHEETUTIL_H__
#define __STYLESHEETUTIL_H__
#include <string>
struct StyleSheetUtil {
static std::string strip(const std::string &data);
static std::vector<std::string> splitCommaSeparatedList(const std::string &data);
};
#endif /* __STYLESHEETUTIL_H__ */

View file

@ -396,6 +396,7 @@ void HtmlBookReader::setProcessPreTag(bool process) {
}
HtmlBookReader::HtmlBookReader(const std::string &baseDirectoryPath, BookModel &model, const PlainTextFormat &format, const std::string &encoding) : HtmlReader(encoding), myBookReader(model), myBaseDirPath(baseDirectoryPath), myFormat(format), myBuildTableOfContent(true), myProcessPreTag(true) {
myFontMap = new FontMap();
}
HtmlBookReader::~HtmlBookReader() {

View file

@ -75,7 +75,7 @@ private:
StyleSheetTable myStyleSheetTable;
shared_ptr<StyleSheetParser> myStyleSheetParser;
FontMap myFontMap;
shared_ptr<FontMap> myFontMap;
int mySpaceCounter;
int myBreakCounter;

View file

@ -229,7 +229,7 @@ void XHTMLTagStyleAction::doAtStart(XHTMLReader &reader, const char **xmlattribu
if (reader.myReadState == XHTML_READ_NOTHING) {
reader.myReadState = XHTML_READ_STYLE;
reader.myTableParser = new StyleSheetTableParser(reader.myPathPrefix, reader.myStyleSheetTable, *reader.myFontMap);
reader.myTableParser = new StyleSheetTableParser(reader.myPathPrefix, reader.myStyleSheetTable, reader.myFontMap);
ZLLogger::Instance().println("CSS", "parsing style tag content");
}
}
@ -269,7 +269,7 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut
parser = new StyleSheetParserWithCache(
cssFile,
MiscUtil::htmlDirectoryPrefix(cssFilePath),
*reader.myFontMap,
0,
reader.myEncryptionMap
);
reader.myFileParsers[cssFilePath] = parser;
@ -280,7 +280,7 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut
parser->parseStream(cssStream);
}
}
parser->applyToTable(reader.myStyleSheetTable);
parser->applyToTables(reader.myStyleSheetTable, *reader.myFontMap);
}
void XHTMLTagLinkAction::doAtEnd(XHTMLReader&) {
@ -673,6 +673,13 @@ bool XHTMLReader::addTextStyleEntry(const std::string tag, const std::string aCl
void XHTMLReader::addTextStyleEntry(const ZLTextStyleEntry &entry) {
if (entry.isFeatureSupported(ZLTextStyleEntry::FONT_FAMILY)) {
ZLLogger::Instance().println("FONT", "Requested font family: " + entry.fontFamily());
shared_ptr<FontEntry> fontEntry = myFontMap->get(entry.fontFamily());
if (fontEntry.isNull()) {
ZLLogger::Instance().println("FONT", "Font entry not found for " + entry.fontFamily());
} else {
const std::string realFamily = myFinalFontMap.put(entry.fontFamily(), fontEntry);
ZLLogger::Instance().println("FONT", "Entry for " + entry.fontFamily() + " stored as " + realFamily);
}
}
myModelReader.addStyleEntry(entry);
}

View file

@ -108,6 +108,7 @@ private:
bool myNewParagraphInProgress;
StyleSheetTable myStyleSheetTable;
shared_ptr<FontMap> myFontMap;
FontMap myFinalFontMap;
std::vector<int> myCSSStack;
std::vector<shared_ptr<ZLTextStyleEntry> > myStyleEntryStack;
int myStylesToRemove;