📄 smil_layout.cpp
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player 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 Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA/* * @$Id: smil_layout.cpp,v 1.46 2007/02/12 14:15:15 jackjansen Exp $ */#include "ambulant/lib/logger.h"#include "ambulant/lib/node.h"#include "ambulant/lib/document.h"#include "ambulant/common/schema.h"#include "ambulant/common/region_dim.h"#include "ambulant/common/layout.h"#include "ambulant/common/preferences.h"#include "ambulant/common/smil_alignment.h"#include "ambulant/smil2/region_node.h"#include "ambulant/smil2/smil_layout.h"#include "ambulant/smil2/test_attrs.h"#include <stack>// #define AM_DBG#ifndef AM_DBG#define AM_DBG if(0)#endifusing namespace ambulant;using namespace smil2;// Factory functioncommon::layout_manager *common::create_smil2_layout_manager(common::factories *factory,lib::document *doc){ return new smil_layout_manager(factory, doc);}smil_layout_manager::smil_layout_manager(common::factories *factory,lib::document *doc): m_schema(common::schema::get_instance()), m_surface_factory(common::create_smil_surface_factory()), m_layout_tree(NULL), m_uses_bgimages(false){ // First find the correct layout section to use. m_layout_section = get_document_layout(doc); // Then scan the DOM tree and create our own tree of region_node objects build_layout_tree(m_layout_section); // Next we create the region_nodes for body nodes that need one (subregion // positioning, etc) build_body_regions(doc); // Next, create the surfaces that correspond to this tree build_surfaces(factory->get_window_factory()); // Now we make sure there is at least one root-layout. This allows us // to use this as the default region. XXXX Should be auto-show eventually. if (m_rootsurfaces.empty()) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: no rootLayouts, creating one"); create_top_surface(factory->get_window_factory(), NULL, NULL); }}smil_layout_manager::~smil_layout_manager(){ m_schema = NULL; std::vector<common::surface_template*>::iterator i; for (i=m_rootsurfaces.begin(); i != m_rootsurfaces.end(); i++) delete (*i); // XXX Delete m_layout_tree tree delete m_layout_tree;}lib::node *smil_layout_manager::get_document_layout(lib::document *doc){ // We first have to find the layout section in the tree lib::node *doc_root = doc->get_root(); lib::node *head = doc_root->get_first_child("head"); if (!head) { lib::logger::get_logger()->trace("smil_layout_manager: no <head> section"); return NULL; } lib::node *layout_root = head->get_first_child("layout"); if (layout_root) { // Check that the type is supported const char *layout_type = layout_root->get_attribute("type"); if (layout_type && strcmp(layout_type, "text/smil-basic-layout") != 0 ) { lib::logger::get_logger()->trace("smil_layout_manager: <layout type=\"%s\"> not supported", layout_type); lib::logger::get_logger()->warn(gettext("Problem with layout in SMIL document")); return NULL; } AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: returning node 0x%x", layout_root); return layout_root; } // Otherwise check for a switch lib::node *layout_switch = head->get_first_child("switch"); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: examining <switch>"); if (layout_switch) { layout_root = layout_switch->down(); while (layout_root) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: examining node 0x%x", layout_root); // Check that it is indeed a <layout> node if (m_schema->get_layout_type((layout_root)->get_qname()) != common::l_layout) { lib::logger::get_logger()->trace("smil_layout_manager: <switch> in <head> should contain only <layout>s"); lib::logger::get_logger()->warn(gettext("Problem with layout in SMIL document")); continue; } // Check that the type is supported const char *layout_type = layout_root->get_attribute("type"); if (layout_type && strcmp(layout_type, "text/smil-basic-layout") != 0 ) { lib::logger::get_logger()->trace("smil_layout_manager: <layout type=\"%s\"> not supported, skipping", layout_type); continue; } test_attrs *tester = new test_attrs(layout_root); if (tester->selected()) { delete tester; AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: returning node 0x%x", layout_root); return layout_root; } AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: skipping layout section due to test attributes"); delete tester; layout_root = layout_root->next(); } } lib::logger::get_logger()->warn(gettext("Problem with layout in SMIL document")); return NULL;}voidsmil_layout_manager::build_layout_tree(lib::node *layout_root){ std::stack<region_node *> stack; // Now we iterate over all the elements, set their dimensions // from the attributes and determine their inheritance lib::node::iterator it; lib::node::iterator end = layout_root->end(); int level = -1; for(it = layout_root->begin(); it != end; it++) { std::pair<bool, lib::node*> pair = *it; if (pair.first) { level++; //if (level == 0) continue; // Skip layout section itself lib::node *n = pair.second; const char *pid = n->get_attribute("id"); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::get_document_layout: examining %s %s", n->get_qname().second.c_str(), (pid?pid:"no-id")); // Find node type common::layout_type tp = m_schema->get_layout_type(n->get_qname()); // First we handle regPoint nodes, which we only store if (tp == common::l_regpoint) { if (pid) { std::string id = pid; m_id2regpoint[id] = n; } else { lib::logger::get_logger()->trace("smil_layout_manager: regPoint node without id attribute"); } continue; } dimension_inheritance di; if (tp == common::l_rootlayout || tp == common::l_toplayout) { di = di_none; } else if (level == 1) { // Toplevel region node di = di_rootlayout; } else { // lower-level region node di = di_parent; } // Put it in the tree region_node *rn = new region_node(n, di); rn->reset(); if (stack.empty()) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::get_document_layout: 0x%x is m_layout_tree", (void*)rn); if(m_layout_tree != NULL) { lib::logger::get_logger()->error("smil_layout_manager: multiple layout roots!"); } m_layout_tree = rn; } else { region_node *parent = stack.top(); parent->append_child(rn); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::get_document_layout: 0x%x is child of 0x%x", (void*)rn, (void*)parent); } // Enter the region ID into the id-mapping if(pid) { std::string id = pid; AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: mapping id %s", pid); m_id2region[id] = rn; } // And the same for the regionName multimap const char *pname = n->get_attribute("regionName"); if(pname) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: mapping regionName %s", pname); m_name2region[pname].push_back(rn); } // See if the node uses background images if (n->get_attribute("backgroundImage")) m_uses_bgimages = true; // And finally into the node->region mapping (for animate) m_node2region[n] = rn; stack.push(rn); } else { level--; stack.pop(); } }}voidsmil_layout_manager::build_body_regions(lib::document *doc) { // Finally we loop over the body nodes, and determine which ones need a region_node // because they use subregion positioning, override background color, etc. lib::node *doc_root = doc->get_root(); lib::node *body = doc_root->get_first_child("body"); if (!body) { lib::logger::get_logger()->error(gettext("Document has no <body> section, nothing to play")); return; } lib::node::const_iterator it; lib::node::const_iterator end = body->end(); for(it = body->begin(); it != end; it++) { std::pair<bool, const lib::node*> pair = *it; if (!pair.first) continue; const lib::node *n = pair.second;#ifdef OLD_SUBREGIONS if (!region_node::needs_region_node(n)) continue;#else if(!test_attrs(n).selected()) continue; if(!n->get_attribute("region") && !region_node::needs_region_node(n) && n->get_local_name() != "area") continue;#endif AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_body_regions: region for 0x%x %s", (void*)n, n->get_local_name().c_str()); region_node *rn = new region_node(n, di_parent); region_node *parent = get_region_node_for(n, false); if (parent) rn->fix_from_region_node(parent); rn->reset(); rn->set_showbackground(false); rn->set_as_subregion(true); if (!parent) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: subregion positioning on default region, node=0x%x, rn=0x%x", (void*)n, (void*)rn); m_default_region_subregions.push_back(rn); } else { parent->append_child(rn); } m_node2region[n] = rn; }} voidsmil_layout_manager::build_surfaces(common::window_factory *wf) { std::stack<common::surface_template*> stack; region_node::iterator it; region_node::const_iterator end = m_layout_tree->end(); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_surfaces called"); assert(wf); // First we check for a root-layout node. This will be used as the parent // of toplevel region nodes. If there is no root-layout but there are // toplevel region nodes we will create it later. common::surface_template *root_surface = NULL; region_node *first_root_layout = m_layout_tree ? m_layout_tree->get_first_child("root-layout") : NULL; if (first_root_layout) { common::bgrenderer *bgrenderer = wf->new_background_renderer(first_root_layout); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_surfaces: create root_layout"); root_surface = create_top_surface(wf, first_root_layout, bgrenderer); assert(root_surface); first_root_layout->set_surface_template(root_surface); } // Loop over all the layout elements, create the regions and root_layouts, // and keep a stack to tie everything together. if (m_layout_tree) { for(it = m_layout_tree->begin(); it != end; it++) { std::pair<bool, region_node*> pair = *it; region_node *rn = pair.second; const lib::node *n = rn->dom_node(); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager: examining %s node 0x%x", n->get_qname().second.c_str(), rn); common::layout_type tag = m_schema->get_layout_type(n->get_qname()); if(tag == common::l_rootlayout) { continue; } if (tag == common::l_layout) continue; if (tag == common::l_none ) { // XXXX Will need to handle switch here too // Assume subregion positioning. AM_DBG lib::logger::get_logger()->trace("smil_layout_manager: skipping <%s> in layout", n->get_qname().second.c_str()); continue; } if (tag == common::l_media) { tag = common::l_region; } if (pair.first) { // On the way down we create the regions and remember // them common::bgrenderer *bgrenderer = wf->new_background_renderer(rn); common::surface_template *surf; const char *pid = n->get_attribute("id"); std::string ident = "<unnamed>"; if(pid) { ident = pid; } // Test that rootlayouts are correctly nested. if (!stack.empty()) { if (tag != common::l_region) { lib::logger::get_logger()->trace("%s: topLayout element inside other element", n->get_sig().c_str()); lib::logger::get_logger()->error(gettext("Problem with layout in SMIL document")); tag = common::l_region; } } // Create the region or the root-layout if (tag == common::l_toplayout) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_surfaces: create topLayout"); surf = create_top_surface(wf, rn, bgrenderer); } else if (tag == common::l_region && !stack.empty()) { common::surface_template *parent = stack.top(); surf = parent->new_subsurface(rn, bgrenderer); } else if (tag == common::l_region && stack.empty()) { // Create root-layout if it doesn't exist yet if (root_surface == NULL) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_surfaces: create default root-layout"); root_surface = create_top_surface(wf, NULL, NULL); } surf = root_surface->new_subsurface(rn, bgrenderer); } else { assert(0); } // Store in the region_node assert(surf); // XXXX Good idea? rn->set_surface_template(surf); // Finally push on to the stack for reference by child nodes stack.push(surf); } else { // On the way back up we only need to pop the stack stack.pop(); } } } // Finally we create the regions for body regions that use subregion // positioning on the default region std::vector<region_node *>::iterator bit; std::vector<region_node *>::const_iterator bend = m_default_region_subregions.end(); for (bit = m_default_region_subregions.begin(); bit != bend; bit++) { region_node *rn = *bit; common::bgrenderer *bgrenderer = wf->new_background_renderer(rn); if (root_surface == NULL) { AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_surfaces: create default root-layout for subregion positioning"); root_surface = create_top_surface(wf, NULL, NULL); } common::surface_template *surf = root_surface->new_subsurface(rn, bgrenderer); assert(surf); // XXXX Good idea? rn->set_surface_template(surf); AM_DBG lib::logger::get_logger()->debug("smil_layout_manager::build_surfaces: subregion 0x%x surface 0x%x", (void*)rn, (void*)surf); }}common::surface_template *smil_layout_manager::create_top_surface(common::window_factory *wf, const region_node *rn, common::bgrenderer *bgrenderer){ common::surface_template *rootrgn;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -