/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */ /* AbiWord * Copyright (C) 2011 Volodymyr Rudyj * Copyright (C) 2007, 2009 Hubert Figuiere * Copyright (C) 2003-2005 Mark Gilbert * Copyright (C) 2002, 2004 Francis James Franklin * Copyright (C) 2001-2002 AbiSource, Inc. * * 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 "ie_exp_HTML_StyleTree.h" IE_Exp_HTML_StyleTree::IE_Exp_HTML_StyleTree(IE_Exp_HTML_StyleTree * parent, const gchar * _style_name, PD_Style * style) : m_pDocument(0), m_parent(parent), m_list(0), m_count(0), m_max(0), m_bInUse(false), m_style_name(_style_name), m_class_name(_style_name), m_class_list(_style_name), m_style(style) { UT_LocaleTransactor t(LC_NUMERIC, "C"); if ((m_style_name == "Heading 1") || (m_style_name == "Heading 2") || (m_style_name == "Heading 3") || (m_style_name == "Normal")) { m_class_name = ""; m_class_list = ""; } else { s_removeWhiteSpace(_style_name, m_class_name, true); m_class_list = m_class_name; } if (parent->class_list() != "") { m_class_list += " "; m_class_list += parent->class_list(); } UT_uint32 j = 0; const gchar * szName = 0; const gchar * szValue = 0; UT_UTF8String name; UT_UTF8String value; while (style->getNthProperty(j++, szName, szValue)) { name = szName; value = szValue; /* map property names to CSS equivalents */ if (name == "text-position") { name = "vertical-align"; if (value == "superscript") value = "super"; else if (value == "subscript") value = "sub"; } else if (name == "bgcolor") { name = "background-color"; } else if (!is_CSS(szName)) continue; /* map property values to CSS equivalents */ if (name == "font-family") { if (!((value == "serif") || (value == "sans-serif") || (value == "cursive") || (value == "fantasy") || (value == "monospace"))) { value = "'"; value += szValue; value += "'"; } } else if ((name == "color") || (name == "background-color")) { if (!value.empty() && (value != "transparent")) { value = UT_colorToHex(szValue, true); } } else if (strstr(name.utf8_str(), "width")) { if (strstr(name.utf8_str(), "border")) { double dPT = UT_convertToDimension(value.utf8_str(), DIM_PT); value = UT_UTF8String_sprintf("%.2fpt", dPT); } else { double dMM = UT_convertToDimension(value.utf8_str(), DIM_MM); value = UT_UTF8String_sprintf("%.1fmm", dMM); } } const std::string & cascade_value = lookup(name.utf8_str()); if (!cascade_value.empty()) if (cascade_value == value) continue; m_map.insert(map_type::value_type(name.utf8_str(), value.utf8_str())); } if ((m_style_name == "Heading 1") || (m_style_name == "Heading 2") || (m_style_name == "Heading 3") || (m_style_name == "Section Heading") || (m_style_name == "Chapter Heading")) { m_map.insert(map_type::value_type("page-break-after", "avoid")); } } IE_Exp_HTML_StyleTree::IE_Exp_HTML_StyleTree(PD_Document * pDocument) : m_pDocument(pDocument), m_parent(0), m_list(0), m_count(0), m_max(0), m_bInUse(false), m_style_name("None"), m_class_name(""), m_class_list(""), m_style(0) { const gchar ** ptr = s_prop_list; while (*ptr) { m_map.insert(map_type::value_type(*ptr, *(ptr + 1))); ptr += 2; } } IE_Exp_HTML_StyleTree::~IE_Exp_HTML_StyleTree() { for (UT_uint32 i = 0; i < m_count; i++) { DELETEP(m_list[i]); } FREEP(m_list); } bool IE_Exp_HTML_StyleTree::add(const gchar * _style_name, PD_Style * style) { if (m_list == 0) { m_list = reinterpret_cast (g_try_malloc(8 * sizeof (IE_Exp_HTML_StyleTree *))); if (m_list == 0) return false; m_max = 8; } if (m_count == m_max) { IE_Exp_HTML_StyleTree ** more = 0; more = reinterpret_cast (g_try_realloc(m_list, (m_max + 8) * sizeof (IE_Exp_HTML_StyleTree *))); if (more == 0) return false; m_list = more; m_max += 8; } IE_Exp_HTML_StyleTree * tree = 0; try { tree = new IE_Exp_HTML_StyleTree(this, _style_name, style); } catch (...) { tree = 0; } if (tree == 0) return false; m_list[m_count++] = tree; return true; } bool IE_Exp_HTML_StyleTree::add(const gchar * _style_name, PD_Document * pDoc) { if ((pDoc == 0) || (_style_name == 0) || (*_style_name == 0)) return false; if (m_parent) return m_parent->add(_style_name, pDoc); if (find(_style_name)) return true; PD_Style * style = 0; pDoc->getStyle(_style_name, &style); if (!style) return false; IE_Exp_HTML_StyleTree * parent = NULL; PD_Style * basis = style->getBasedOn(); const gchar * parent_name = NULL; if (basis && basis->getAttribute(PT_NAME_ATTRIBUTE_NAME, parent_name) && strcmp(_style_name, parent_name) != 0) { parent = const_cast (find(basis)); if (parent == NULL) { const gchar * basis_name = 0; basis->getAttribute(PT_NAME_ATTRIBUTE_NAME, basis_name); if (!basis_name) return false; if (basis->getBasedOn() && basis->getBasedOn()->getName() && !strcmp(_style_name, basis->getBasedOn()->getName())) { parent = this; } else { if (!add(basis_name, pDoc)) return false; parent = const_cast (find(basis)); } } } else parent = this; if (!parent) { UT_ASSERT_NOT_REACHED(); return false; } return parent->add(_style_name, style); } void IE_Exp_HTML_StyleTree::inUse() { m_bInUse = true; if (m_parent) m_parent->inUse(); } const IE_Exp_HTML_StyleTree * IE_Exp_HTML_StyleTree::findAndUse(const gchar * _style_name) { const IE_Exp_HTML_StyleTree * style_tree = find(_style_name); if (style_tree) { IE_Exp_HTML_StyleTree * tree = const_cast (style_tree); tree->inUse(); } return style_tree; } const IE_Exp_HTML_StyleTree * IE_Exp_HTML_StyleTree::find(const gchar * _style_name) const { if (m_style_name == _style_name) return this; const IE_Exp_HTML_StyleTree * tree = 0; for (UT_uint32 i = 0; i < m_count; i++) { tree = m_list[i]->find(_style_name); if (tree) break; } return tree; } const IE_Exp_HTML_StyleTree * IE_Exp_HTML_StyleTree::find(PD_Style * style) const { const gchar * _style_name = 0; style->getAttribute(PT_NAME_ATTRIBUTE_NAME, _style_name); if (!_style_name) return NULL; return find(_style_name); } bool IE_Exp_HTML_StyleTree::descends(const gchar * _style_name) const { if (m_parent == 0) return false; // the name comparison has to be be case insensitive if (!g_ascii_strcasecmp(m_style_name.utf8_str(), _style_name)) return true; return m_parent->descends(_style_name); } const std::string & IE_Exp_HTML_StyleTree::lookup(const std::string & prop_name) const { static std::string empty; map_type::const_iterator prop_iter = m_map.find(prop_name); if (prop_iter == m_map.end()) { if (m_parent) { return m_parent->lookup(prop_name); } else { return empty; } } return (*prop_iter).second; } IE_Exp_HTML_StyleListener::IE_Exp_HTML_StyleListener(IE_Exp_HTML_StyleTree* styleTree): m_pStyleTree(styleTree) { } void IE_Exp_HTML_StyleListener::styleCheck(PT_AttrPropIndex api) { const PP_AttrProp * pAP = 0; bool bHaveProp = (api ? (m_pStyleTree->getDocument()->getAttrProp(api, &pAP)) : false); if (bHaveProp && pAP) { const gchar * szStyle = NULL; bool have_style = pAP->getAttribute(PT_STYLE_ATTRIBUTE_NAME, szStyle); if (have_style && szStyle) { m_pStyleTree->findAndUse(szStyle); } } } bool IE_Exp_HTML_StyleListener::populate(fl_ContainerLayout* /*sfh*/, const PX_ChangeRecord * pcr) { switch (pcr->getType()) { case PX_ChangeRecord::PXT_InsertSpan: styleCheck(pcr->getIndexAP()); break; case PX_ChangeRecord::PXT_InsertObject: styleCheck(pcr->getIndexAP()); break; default: break; } return true; } bool IE_Exp_HTML_StyleListener::populateStrux(pf_Frag_Strux* /*sdh*/, const PX_ChangeRecord * pcr, fl_ContainerLayout* * psfh) { UT_return_val_if_fail(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux, false); *psfh = 0; // we don't need it. const PX_ChangeRecord_Strux * pcrx = static_cast (pcr); switch (pcrx->getStruxType()) { case PTX_Block: styleCheck(pcr->getIndexAP()); break; case PTX_SectionFootnote: styleCheck(pcr->getIndexAP()); break; case PTX_SectionEndnote: styleCheck(pcr->getIndexAP()); break; default: break; } return true; } bool IE_Exp_HTML_StyleListener::change(fl_ContainerLayout* /*sfh*/, const PX_ChangeRecord * /*pcr*/) { UT_ASSERT_HARMLESS(0); // this function is not used. return false; } bool IE_Exp_HTML_StyleListener::insertStrux(fl_ContainerLayout* /*sfh*/, const PX_ChangeRecord * /*pcr*/, pf_Frag_Strux* /*sdh*/, PL_ListenerId /* lid */, void (* /*pfnBindHandles*/)(pf_Frag_Strux* /* sdhNew */, PL_ListenerId /* lid */, fl_ContainerLayout* /* sfhNew */)) { UT_ASSERT_HARMLESS(0); // this function is not used. return false; } bool IE_Exp_HTML_StyleListener::signal(UT_uint32 /* iSignal */) { UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); return false; }