Package org.pentaho.reporting.libraries.css.resolver.impl

Source Code of org.pentaho.reporting.libraries.css.resolver.impl.DefaultStyleResolver

/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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 Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation..  All rights reserved.
*/

package org.pentaho.reporting.libraries.css.resolver.impl;

import java.util.ArrayList;
import java.util.Arrays;

import org.pentaho.reporting.libraries.css.PageAreaType;
import org.pentaho.reporting.libraries.css.PseudoPage;
import org.pentaho.reporting.libraries.css.dom.DefaultLayoutStyle;
import org.pentaho.reporting.libraries.css.dom.DocumentContext;
import org.pentaho.reporting.libraries.css.dom.LayoutElement;
import org.pentaho.reporting.libraries.css.dom.LayoutStyle;
import org.pentaho.reporting.libraries.css.model.CSSDeclarationRule;
import org.pentaho.reporting.libraries.css.model.CSSPageAreaRule;
import org.pentaho.reporting.libraries.css.model.CSSPageRule;
import org.pentaho.reporting.libraries.css.model.CSSStyleRule;
import org.pentaho.reporting.libraries.css.model.StyleKey;
import org.pentaho.reporting.libraries.css.model.StyleKeyRegistry;
import org.pentaho.reporting.libraries.css.namespace.NamespaceCollection;
import org.pentaho.reporting.libraries.css.namespace.NamespaceDefinition;
import org.pentaho.reporting.libraries.css.namespace.Namespaces;
import org.pentaho.reporting.libraries.css.parser.StyleSheetParserUtil;
import org.pentaho.reporting.libraries.css.resolver.StyleResolver;
import org.pentaho.reporting.libraries.css.resolver.StyleRuleMatcher;
import org.pentaho.reporting.libraries.css.selectors.CSSSelector;
import org.pentaho.reporting.libraries.css.selectors.SelectorWeight;
import org.pentaho.reporting.libraries.css.values.CSSInheritValue;
import org.pentaho.reporting.libraries.css.values.CSSValue;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;


/**
* A cascading style resolver. This resolver follows the cascading rules
* as outlined by the Cascading Stylesheet Standard.
*
* @author Thomas Morgner
*/
public class DefaultStyleResolver extends AbstractStyleResolver
{
  private boolean strictStyleMode;
  private StyleRuleMatcher styleRuleMatcher;
  private StyleKey[] inheritedKeys;

  public DefaultStyleResolver()
  {
  }

  public void initialize(final DocumentContext layoutProcess)
  {
    super.initialize(layoutProcess);
    this.styleRuleMatcher = new SimpleStyleRuleMatcher();
    this.styleRuleMatcher.initialize(layoutProcess);
//    this.strictStyleMode = Boolean.TRUE.equals
//            (documentContext.getMetaAttribute(DocumentContext.STRICT_STYLE_MODE));

    loadInitialStyle(layoutProcess);
  }

  // This one is expensive too: 6%
  protected void resolveOutOfContext(final LayoutElement element)
  {
    // as this styleresolver is not statefull, we can safely call the resolve
    // style method. A statefull resolver would have to find other means.
    resolveStyle(element);
  }

  /**
   * Performs tests, whether there is a pseudo-element definition for the given
   * element. The element itself can be a pseudo-element as well.
   *
   * @param element
   * @param pseudo
   * @return
   */
  public boolean isPseudoElementStyleResolvable(final LayoutElement element,
                                                final String pseudo)
  {
    return styleRuleMatcher.isMatchingPseudoElement(element, pseudo);
  }

  /**
   * Resolves the style. This is guaranteed to be called in the order of the
   * document elements traversing the document tree using the
   * 'deepest-node-first' strategy.
   * (8% just for the first class calls (not counting the calls comming from
   * resolveAnonymous (which is another 6%))
   *
   * @param element the elemen that should be resolved.
   */
  public void resolveStyle(final LayoutElement element)
  {
    // this is a three stage process
    final StyleKey[] keys = getKeys();

//    Log.debug ("Resolving style for " +
//            layoutContext.getTagName() + ":" +
//            layoutContext.getPseudoElement());

    final LayoutElement parent = element.getParentLayoutElement();
    final LayoutStyle initialStyle = getInitialStyle();
    final LayoutStyle style = element.getLayoutStyle();

    // Stage 0: Initialize with the built-in defaults
    // The copy will return false if it couldn't do the copy automatically
    if (style.copyFrom(initialStyle) == false)
    {
      // manually copy all styles from the initial style-set..
      for (int i = 0; i < keys.length; i++)
      {
        final StyleKey key = keys[i];
        style.setValue(key, initialStyle.getValue(key));
      }
    }

    // Stage 1a: Add the parent styles (but only the one marked as inheritable).

    // If our element has a parent, get the parent's style information
    // so we can "inherit" the styles that support that kind of thing
    if (parent != null)
    {
      final LayoutStyle parentStyle;
      parentStyle = parent.getLayoutStyle();
      final StyleKey[] inheritedKeys = getInheritedKeys();
      for (int i = 0; i < inheritedKeys.length; i++)
      {
        final StyleKey key = inheritedKeys[i];
        style.setValue(key, parentStyle.getValue(key));
      }
    }

    // At this point, the parentStyle contains the "foundation" from which
    // the current element's style information will come....

    // Stage 1b: Find all matching stylesheet styles for the given element.
    performSelectionStep(element, style);

    // Stage 1c: Add the contents of the style attribute, if there is one ..
    // the libLayout style is always added: This is a computed style and the hook
    // for a element neutral user defined tweaking ..

    final Object libLayoutStyleValue = element.getAttribute(Namespaces.LIBLAYOUT_NAMESPACE, "style");
    // You cannot override element specific styles with that. So an HTML-style
    // attribute has more value than a LibLayout-style attribute.
    addStyleFromAttribute(element, libLayoutStyleValue);

    if (strictStyleMode)
    {
      performStrictStyleAttr(element);
    }
    else
    {
      performCompleteStyleAttr(element);
    }

    // Stage 2: Compute the 'specified' set of values.
    // Find all explicitly inherited styles and add them from the parent.
    final CSSInheritValue inheritInstance = CSSInheritValue.getInstance();
    if (parent == null)
    {
      for (int i = 0; i < keys.length; i++)
      {
        final StyleKey key = keys[i];
        final Object value = style.getValue(key);
        if (inheritInstance.equals(value))
        {
          style.setValue(key, initialStyle.getValue(key));
        }
      }
    }
    else
    {
      final LayoutStyle parentStyle = parent.getLayoutStyle();
      for (int i = 0; i < keys.length; i++)
      {
        final StyleKey key = keys[i];
        final Object value = style.getValue(key);
        if (inheritInstance.equals(value))
        {
          final CSSValue parentValue = parentStyle.getValue(key);
          if (parentValue == null)
          {
            style.setValue(key, initialStyle.getValue(key));
          }
          else
          {
            style.setValue(key, parentValue);
          }
        }
      }
    }

  }

  private StyleKey[] getInheritedKeys()
  {
    if (inheritedKeys == null)
    {
      final StyleKey[] keys = getKeys();
      final ArrayList inheritedKeysList = new ArrayList();
      for (int i = 0; i < keys.length; i++)
      {
        final StyleKey key = keys[i];
        if (key.isInherited())
        {
          inheritedKeysList.add(key);
        }
      }
      inheritedKeys = (StyleKey[])
          inheritedKeysList.toArray(new StyleKey[inheritedKeysList.size()]);
    }
    return inheritedKeys;
  }

  /**
   * Check, whether there is a known style attribute for the element's namespace
   * and if so, grab its value. This method uses strict conformance to the XML
   * rules and thus it does not evaluate foreign styles.
   * <p/>
   *
   * @param node
   */
  private void performStrictStyleAttr(final LayoutElement node)
  {
    final String namespace = node.getNamespace();
    if (namespace == null)
    {
      return;
    }

    final NamespaceCollection namespaces = getNamespaces();
    final NamespaceDefinition ndef = namespaces.getDefinition(namespace);
    if (ndef == null)
    {
      return;
    }

    //final AttributeMap attributes = layoutContext.getAttributes();
    final String[] styleAttrs = ndef.getStyleAttribute
        (node.getTagName());
    for (int i = 0; i < styleAttrs.length; i++)
    {
      final String attr = styleAttrs[i];
      final Object styleValue = node.getAttribute(namespace, attr);
      addStyleFromAttribute(node, styleValue);
    }
  }

  /**
   * Check, whether there are known style attributes and if so, import them.
   * This method uses a relaxed syntax and imports all known style attributes
   * ignoring the element's defined namespace. This allows to add styles to
   * elements which would not support styles otherwise, but may have ..
   * chaotic .. side effects.
   * <p/>
   *
   * @param node
   */
  private void performCompleteStyleAttr(final LayoutElement node)
  {
    final NamespaceCollection namespaces = getNamespaces();
    final String[] namespaceNames = namespaces.getNamespaces();

    for (int i = 0; i < namespaceNames.length; i++)
    {
      final String namespace = namespaceNames[i];
      final NamespaceDefinition ndef = namespaces.getDefinition(namespace);
      if (ndef == null)
      {
        continue;
      }

      final String[] styleAttrs = ndef.getStyleAttribute(node.getTagName());
      for (int x = 0; x < styleAttrs.length; x++)
      {
        final String attr = styleAttrs[x];
        final Object styleValue = node.getAttribute(namespace, attr);
        addStyleFromAttribute(node, styleValue);
      }
    }
  }

  private void addStyleFromAttribute(final LayoutElement node,
                                     final Object styleValue)
  {
    if (styleValue == null)
    {
      return;
    }

    if (styleValue instanceof String)
    {
      final String styleText = (String) styleValue;
      final ResourceManager resourceManager = getDocumentContext().getResourceManager();
      final CSSDeclarationRule rule = StyleSheetParserUtil.getInstance().parseStyleRule
          (null, styleText, null, null, resourceManager, StyleKeyRegistry.getRegistry());
      if (rule != null)
      {
        copyStyleInformation(node.getLayoutStyle(), rule, node);
      }
    }
    else if (styleValue instanceof CSSDeclarationRule)
    {
      final CSSDeclarationRule rule = (CSSDeclarationRule) styleValue;
      copyStyleInformation(node.getLayoutStyle(), rule, node);
    }
  }

  /**
   * Todo: Make sure that the 'activeStyles' are sorted and then apply them with the
   * lowest style first. All Matching styles have to be added.
   */
  private void performSelectionStep(final LayoutElement element,
                                    final LayoutStyle parentStyle)
  {
    final CSSStyleRule[] activeStyleRules = styleRuleMatcher.getMatchingRules(element);

    // sort ...
    Arrays.sort(activeStyleRules, new CSSStyleRuleComparator());
    SelectorWeight oldSelectorWeight = null;
    for (int i = 0; i < activeStyleRules.length; i++)
    {
      final CSSStyleRule activeStyleRule = activeStyleRules[i];
      final CSSSelector selector = activeStyleRule.getSelector();
      final SelectorWeight activeWeight = selector.getWeight();

      if (oldSelectorWeight != null)
      {
        if (oldSelectorWeight.compareTo(activeWeight) > 0)
        {
          oldSelectorWeight = activeWeight;
          continue;
        }
      }

      oldSelectorWeight = activeWeight;
      copyStyleInformation(parentStyle, activeStyleRule, element);
    }
  }

  public StyleResolver deriveInstance()
  {
    return this;
  }

  public LayoutStyle resolvePageStyle(final CSSValue pageName,
                                      final PseudoPage[] pseudoPages,
                                      final PageAreaType pageArea)
  {
    final DefaultLayoutStyle style = new DefaultLayoutStyle();

    final CSSPageRule[] pageRule =
        styleRuleMatcher.getPageRule(pageName, pseudoPages);
    for (int i = 0; i < pageRule.length; i++)
    {
      final CSSPageRule cssPageRule = pageRule[i];
      copyStyleInformation(style, cssPageRule, null);

      final int rc = cssPageRule.getRuleCount();
      for (int r = 0; r < rc; r++)
      {
        final CSSPageAreaRule rule = cssPageRule.getRule(r);
        if (rule.getPageArea().equals(pageArea))
        {
          copyStyleInformation(style, rule, null);
        }
      }
    }
    return style;
  }
}
TOP

Related Classes of org.pentaho.reporting.libraries.css.resolver.impl.DefaultStyleResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.