// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/**
 * Document APIs.
 * @class DvtSvgDocumentUtils
 */
var DvtSvgDocumentUtils = function(){};

DvtObj.createSubclass(DvtSvgDocumentUtils, DvtDocumentUtils, "DvtSvgDocumentUtils");

// TODO JSDoc
// Return displayable
DvtSvgDocumentUtils.elementFromPoint = function(posX, posY) {
  var domObj = document.elementFromPoint(posX, posY); 
  while (domObj) {
    if (domObj._obj && domObj._obj.getObj && domObj._obj.getObj()) {
        return domObj._obj.getObj();
    }
    domObj = domObj.parentNode;
  }
  return null;
};

/**
 * Wrapper for the elementFromPoint function that uses clientX and clientY coordinates 
 * from the touch to find a corresponding displayable object
 * @param {DvtTouch} touch The touch being passed in to evaluate the element it corresponds to
 * @return {DvtDisplayable} displayable The dom object the touch corresponds to
 */
DvtSvgDocumentUtils.elementFromTouch = function(touch) {
  return this.elementFromPoint(touch.clientX, touch.clientY);
};

// TODO JSDoc
// Return coordinates relative to stage
DvtSvgDocumentUtils.getStageRelativePosition = function(stage, x, y) {
  var svgPos = DvtSvgDocumentUtils.getStageAbsolutePosition(stage);
  var xPos = x - svgPos.x;
  var yPos = y - svgPos.y;
  return new DvtPoint(xPos, yPos);
}

/**
 * Return coordinates relative to the page
 * @param {DvtStage} stage
 * @param {Number} x
 * @param {Number} y
 */
DvtSvgDocumentUtils.getPageRelativePosition = function(stage, x, y)
{
  var svgPos = DvtSvgDocumentUtils.getStageAbsolutePosition(stage);
  var xPos = x + svgPos.x;
  var yPos = y + svgPos.y;
  return new DvtPoint(xPos, yPos);
}

/**
 * Returns the absolute page coordinates of the stage.
 * @param {DvtStage}
 * @return {DvtPoint}
 */
DvtSvgDocumentUtils.getStageAbsolutePosition = function(stage) {
  var svgRoot = stage.getImpl().getSVGRoot();
  
  // Use a reference element at the same position at the SVG whenever possible.  The browser functions used in DvtAgent's
  // getElementPosition do not always return the correct values for SVG elements, especially in Firefox.  Note that we 
  // can ensure the presence of a parent div at the same coordinates across all our supported frameworks, so this
  // issue will never occur in the real product.
  var referenceElem = svgRoot;
  if (window && window.AdfAgent) 
    referenceElem = svgRoot.parentNode;
  else if (svgRoot.parentNode && svgRoot.parentNode.firstChild == svgRoot) // Otherwise require element to be the first child      
    referenceElem = svgRoot.parentNode;
  
  // Note: As mentioned above, this returns the wrong position in Firefox for SVG elements.
  var svgPos = DvtAgent.getElementPosition(referenceElem);
  
  return new DvtPoint(parseInt(svgPos.x), parseInt(svgPos.y));
}

/**
 * Returns true if SVG filters are supported.
 * @return {boolean}
 */
DvtSvgDocumentUtils.isFilterSupported = function(stage) {
  // Filters not supported in IE, Safari < 6, Android
  return !DvtAgent.isPlatformIE() && 
         !(DvtAgent.isBrowserSafari() && DvtAgent.getVersion() < 536) &&
         !(DvtAgent.isTouchDevice() && !DvtAgent.isBrowserSafari());
}

DvtSvgDocumentUtils.isStrokeTimeoutRequired = function() {
    return DvtAgent.isBrowserChrome();
}

/*
 * Whether or not events in SVG are received on regions that are visually clipped such that they are not visible
 */
DvtSvgDocumentUtils.isEventAvailableOutsideClip = function() {
    return DvtAgent.isBrowserSafari();
}

/*
 * Bug #12805402: In Firefox 4, horizontal/vertical polylines must be bent by 0.01 pixes to show up when fitlers are used
 */
DvtSvgDocumentUtils.isFilterStraightLineAdjustmentNeeded = function() {
    return DvtAgent.isPlatformGecko();
}

/**
 * Work around bug 16575172, where removing filters from children or 
 * removing children that have filters can leave behind rendering artifacts 
 * in Firefox.
 * @param displayable The displayable to refresh.
 */
DvtSvgDocumentUtils.fixGeckoContainerForFilter = function(displayable) {
  if (displayable && DvtAgent.isPlatformGecko()) {
    var elem = displayable.getImpl().getElem();
    if (elem) {
      var transformAttr = DvtSvgUtils.getAttrNullNS(elem, 'transform');
      //error message logged to Firefox console if transformAttr is null,
      //so initialize it to identity matrix instead
      if (!transformAttr) {
        transformAttr = "matrix(1 0 0 1 0 0)";
      }
      DvtSvgUtils.setAttrNullNS(elem, 'transform', transformAttr);
    }
  }
}

/**
 * Cancel a DOM event.
 * 
 * @param {object}  e  event object to cancel
 */
DvtSvgDocumentUtils.cancelDomEvent = function(e)
{
  //if (!e)
  //{
  //  e = window.event;
  //}
  if (e)
  {
    if (e.stopPropagation)
      e.stopPropagation();
    if (e.preventDefault)
      e.preventDefault();
    e.cancelBubble = true;
    e.cancel = true;
    e.returnValue = false;
  }
}
/**
 * DvtSvgImageLoader.loadImage("pic.png", function(image) {
 *   alert(image.width);
 *   alert(image.height);
 * });
 * 
 */

/*
 * DvtSvgImageLoader
 */
var DvtSvgImageLoader = { _cache: {} };

DvtObj.createSubclass(DvtSvgImageLoader, DvtObj, "DvtSvgImageLoader");

/**
 * Copied from AdfIEAgent and AdfAgent
 * Adds an event listener that fires in the non-Capture phases for the specified
 * eventType.  There is no ordering guaranteee, nor is there a guarantee
 * regarding the number of times that an event listener will be called if
 * it is added to the same element multiple times.
 */
DvtSvgImageLoader.addBubbleEventListener = function(element, type, listener) 
{
  if (window.addEventListener) {
    DvtSvgUtils.addDomEventListener(element, type, listener, false);
    return true;
  } 
  // Internet Explorer
  else if (window.attachEvent) {
    element.attachEvent("on" + type, listener);
    return true;
  }
  else {
    return false;
  }
};


/**
 * @this {DvtSvgImageLoader}
 * Load an image.
 * 
 * @param src URL of the image to load
 * @param onComplete function to call when the image is loaded
 * 
 * @return image if image is already loaded
 *         otherwise null
 */
DvtSvgImageLoader.loadImage = function(src, onComplete) {
  //first look for a cached copy of the image
  var entry = this._cache[src];

  //if cached image found, use it
  if (entry) {
    // if image is loading, add listener to queue
    if (entry._image) {
      DvtSvgImageLoader._addListenerToQueue(entry._listeners, onComplete);
    }
    // if image is loaded, call onComplete function
    else {
      if (onComplete) {
        onComplete(entry);
      }
      // no handler, just return image width and height
      return entry;
    }
  }
  //if cached image not found, load the new image
  else {
    this.loadNewImage(src, onComplete);
  }
  return null;
};

/**
 * @this {DvtSvgImageLoader}
 * Load a new image.
 * 
 * @param src URL of the image to load
 * @param onComplete function to call when the image is loaded 
 */
DvtSvgImageLoader.loadNewImage = function(src, onComplete) {

  // create img element
  var image = document.createElement('img');

  // add a new entry to the image cached
  // depending on the state, entry value contains different attributes
  // when image is loading, entry contains image element and listeners
  // when image is loaded, entry contains image width and height
  var newEntry = {
    _listeners:[], 
    url: src,
    _image: image
  };
  if (onComplete) {
//    newEntry._listeners.push(onComplete);
    DvtSvgImageLoader._addListenerToQueue(newEntry._listeners, onComplete);
  }

  this._cache[src] = newEntry;

  DvtSvgImageLoader.addBubbleEventListener(image, 'load', function(e) {
      // copy width and height to entry and delete image element
      newEntry.width = image.width;
      newEntry.height = image.height;
      delete newEntry._image;

      // notify all listeners image loaded and delete all listeners
      var i;
      var len = newEntry._listeners.length;
      for (i = 0; i < len; i++) {
        // if there is a listener
        if (newEntry._listeners[i]) {
        newEntry._listeners[i](newEntry);
        }
      }
      delete newEntry._listeners;
    });

  image.src = src;

};


// add a listener to the queue only if it doesn't already exist
DvtSvgImageLoader._addListenerToQueue = function(queue, listener) {
  if (listener) {
    for (var i = 0; i < queue.length; i++) {
      if (queue[i] === listener)
        return;
    }
    queue.push(listener);
  }
};

/**
 * @constructor
 * Wrapper class providing access to SVG Events.
 * @extends DvtObj
 * @class DvtSvgBaseEvent
 * <p>The supported fields are:
 * <ul>
 * <li>target</li>
 * <li>type</li>
 * </ul>
 * <p>
 */
var DvtSvgBaseEvent = function(event) {
  this.Init(event);
}

DvtObj.createSubclass(DvtSvgBaseEvent, DvtObj, "DvtSvgBaseEvent");

/**
 * @protected
 * @param {MouseEvent} the DOM Mouse Event
 */
DvtSvgBaseEvent.prototype.Init = function(event) {
  // Save the event
  this._event = event;
  this._isPropagationStopped = false;

  // Find the DvtObj corresponding to the event target
  this.target = DvtSvgBaseEvent.FindDisplayable(event.target);

  this.type = event.type;
}

// TODO JSDoc
DvtSvgBaseEvent.prototype.getNativeEvent = function() {
  return this._event;
}

DvtSvgBaseEvent.prototype.preventDefault = function() {
    this._event.preventDefault();
} 

DvtSvgBaseEvent.prototype.stopPropagation = function() {
    if (this._event.stopPropagation)
      this._event.stopPropagation();
    this._event.cancelBubble = true;
    this._event.cancel = true;
    this._event.returnValue = false;
    this._isPropagationStopped = true;
} 

DvtSvgBaseEvent.prototype.isPropagationStopped = function() {
  return this._isPropagationStopped;
} 

/**
 * Given an SVG DOM target, returns the corresponding DvtDisplayable.
 * @return {DvtDisplayable} The corresponding displayable, if any.
 */
DvtSvgBaseEvent.FindDisplayable = function(target) {
  while(target) {
    // If this object has a displayable, return it
    if(target._obj && target._obj.getObj && target._obj.getObj())
      return target._obj.getObj();
    else // Otherwise look at the parent
      target = target.parentNode;
  }
  
  // Displayable not found, return null
  return null;
}
var DvtSvgEventFactory = new Object();

DvtObj.createSubclass(DvtSvgEventFactory, DvtObj, "DvtSvgEventFactory");

// Note: this doesn't need to live in the factory because it will always be called
// by impl specific code looking to wrap the event.
// TODO JSDoc
DvtSvgEventFactory.newEvent = function(nativeEvent, context) {
  // TODO detect the event type and perform wrapping as needed
  var eventType = nativeEvent.type;
  if (eventType == DvtTouchEvent.TOUCHSTART || eventType == DvtTouchEvent.TOUCHMOVE || eventType == DvtTouchEvent.TOUCHEND || eventType == DvtTouchEvent.TOUCHCANCEL) {
      return new DvtSvgTouchEvent(nativeEvent, context);
  } 
  else if(eventType == DvtKeyboardEvent.KEYDOWN || eventType == DvtKeyboardEvent.KEYUP) {
      return new DvtSvgKeyboardEvent(nativeEvent);
  }  
  else {
      // TODO check for type
      //BUG FIX 14187937: if the native event is the same as the last one, return the stored logical event,
      //otherwise create a new logical event and store the pair of events
      if (context._nativeEvent != nativeEvent) {
        context._nativeEvent = nativeEvent;
        context._logicalEvent = new DvtSvgMouseEvent(nativeEvent);
      }
      return context._logicalEvent;
  }
};

/**
 * Returns a DvtSvgMouseEvent that wraps the given keyboard event.  The given stageX and stageY coordinates are used to
 * compute the DvtSvgMouseEvent's pageX and pageY fields
 * 
 * @param {DvtKeyboardEvent} keyboardEvent
 * @param {DvtContext} context
 * @param {String} eventType
 * @param {DvtStage} stage
 * @param {Number} stageX
 * @param {Number} stageY
 * @return {DvtSvgMouseEvent}
 */
DvtSvgEventFactory.generateMouseEventFromKeyboardEvent = function(keyboardEvent, context, eventType, stage, stageX, stageY)
{
  var nativeEvent = null;
  
  if (document.createEvent) 
  {
    nativeEvent = document.createEvent("MouseEvents");
    
    var pageCoord = DvtSvgDocumentUtils.getPageRelativePosition(stage, stageX, stageY);
    
    nativeEvent.initMouseEvent(eventType, true, true, window, 1, pageCoord.x, pageCoord.y, pageCoord.x, pageCoord.y,
                         keyboardEvent.ctrlKey, keyboardEvent.altKey, keyboardEvent.shiftKey, keyboardEvent.metaKey,
                         0, null);
  }    
  
  if(nativeEvent)
  {
    var mouseEvent = DvtSvgEventFactory.newEvent(nativeEvent, context);
    mouseEvent.target = keyboardEvent.target;
    return mouseEvent;
  }
  else
    return null;
}
/**
 * @constructor
 * Wrapper class providing access to SVG Keyboard Events.
 * @extends DvtKeyboardEvent
 * @class DvtSvgKeyboardEvent
 * <p>The supported fields are:
 * <ul>
 * <li>altKey</li>
 * <li>ctrlKey</li>
 * <li>shiftKey</li>
 * <li>charCode</li>
 * <li>keyCode</li>
 * </ul>
 * <p>
 */
// TODO: add support for a source and target fields
var DvtSvgKeyboardEvent = function(event) {
  this.Init(event);
}

DvtObj.createSubclass(DvtSvgKeyboardEvent, DvtKeyboardEvent, "DvtSvgKeyboardEvent");


/**
 * @protected
 * @param {KeyboardEvent} the DOM Keyboard Event
 */
DvtSvgKeyboardEvent.prototype.Init = function(event) {
  DvtSvgKeyboardEvent.superclass.Init.call( this, 
                                            event.type, 
                                            event.bubbles,
                                            event.cancelable,
                                            event.view,
                                            event.charCode,
                                            event.keyCode,
                                            event.keyLocation,
                                            event.ctrlKey,
                                            event.altKey,
                                            event.shiftKey,
                                            event.repeat,
                                            event.locale );
                                            
  // TODO - what about event.target?                                            
  this._event = event;
}

/**
 * @override
 */
DvtSvgKeyboardEvent.prototype.getNativeEvent = function()
{
  return this._event;
}

/**
 * @override
 */
DvtSvgKeyboardEvent.prototype.preventDefault = function() {
    this._event.preventDefault();
} 

/**
 * @override
 */
DvtSvgKeyboardEvent.prototype.stopPropagation = function() {
    if (this._event.stopPropagation)
      this._event.stopPropagation();
    this._event.cancelBubble = true;
    this._event.cancel = true;
    this._event.returnValue = false;
} 
/**
 * @constructor
 * Wrapper class providing access to SVG Mouse Events.
 * @extends DvtSvgBaseEvent
 * @class DvtSvgMouseEvent
 * <p>The supported fields are:
 * <ul>
 * <li>ctrlKey</li>
 * <li>relatedTarget</li>
 * <li>target</li>
 * <li>type</li>
 * </ul>
 * <p>
 */
var DvtSvgMouseEvent = function(event) {
  this.Init(event);
}

DvtObj.createSubclass(DvtSvgMouseEvent, DvtSvgBaseEvent, "DvtSvgMouseEvent");

/**
 * @protected
 * @param {MouseEvent} the DOM Mouse Event
 */
DvtSvgMouseEvent.prototype.Init = function(event) {

  DvtSvgMouseEvent.superclass.Init.call(this, event);
  
  // Find the DvtObj corresponding to the event target
  if(event.relatedTarget != null)
    this.relatedTarget = DvtSvgBaseEvent.FindDisplayable(event.relatedTarget);  
  
  // Copy the remaining information
  this.button = event.button;
  this.ctrlKey = event.ctrlKey || event.metaKey;
  this.shiftKey = event.shiftKey;
  this.pageX = event.pageX;
  this.pageY = event.pageY;
  //Bug 17369581: Flag indicates if the event is modified for Internet Explorer
  this._isEventModifiedForIE = false;

  if (event.wheelDelta != null)
    this.wheelDelta = event.wheelDelta/40;
  else if(event.deltaY != null) {
    this.deltaMode = event.deltaMode;
    this.deltaY = event.deltaY;
    
    // Approximate the wheel delta from the deltaY and deltaMode
    if(event.deltaMode == event.DOM_DELTA_LINE)
      this.wheelDelta = -event.deltaY;
    else if(event.deltaMode == event.DOM_DELTA_PIXEL)
      this.wheelDelta = -event.deltaY/15;  
  }
  else
    this.wheelDelta = event.detail;
};

/**
 * Modify the event for IE with the new event type and new target element
 * 
 * @public
 * @param {string} newType  New Mouse Event type
 * @param {DOMElement} newTargetElement  New SVG DOM Target Element
 */
DvtSvgMouseEvent.prototype.modifyEventForIE = function(newType, newTargetElement) {
  //Bug 17369581: Set the event type as newType, relatedTarget as current target and target as displayable of newTargetElement
  //This will target the event to newTargetElement and change the event type 
  //Modify the event target only once because every DvtSvgMouseEvent instance has unique native event.
  //Doing this more than once will make relatedTarget and target same as displayable of newTargetElement
  if(!this._isEventModifiedForIE) {
    this.type = newType;
    this.relatedTarget = this.target;
    this.target = DvtSvgBaseEvent.FindDisplayable(newTargetElement);
    this._isEventModifiedForIE = true;
  }
};

/**
 * @constructor
 * Wrapper class providing access to SVG Touch Events.
 * @extends DvtSvgBaseEvent
 * @class DvtSvgTouchEvent
 * <p>The supported fields are:
 * <ul>
 * <li>touches</li>
 * <li>targetTouches</li>
 * <li>changedTouches</li>
 * <li>target</li>
 * <li>type</li>
 * </ul>
 * <p>
 */
var DvtSvgTouchEvent = function(event, context) {
  this.Init(event, context);
}

DvtObj.createSubclass(DvtSvgTouchEvent, DvtSvgBaseEvent, "DvtSvgTouchEvent");

/**
 * @protected
 * @param {TouchEvent} the DOM Touch Event
 * @param {DvtContext} context 
 */
DvtSvgTouchEvent.prototype.Init = function(event, context) {

  DvtSvgTouchEvent.superclass.Init.call(this, event);
  // Convert touchcancel to touchend
  if (event.type == DvtTouchEvent.TOUCHCANCEL) {
      this.type = DvtTouchEvent.TOUCHEND;
  }
  this._nativeTouches = event.touches;
  this._nativeTargetTouches = event.targetTouches;
  this._nativeChangedTouches = event.changedTouches;
  this.touches = DvtSvgTouchEvent.createTouchArray(event.touches);
  this.targetTouches = DvtSvgTouchEvent.createTouchArray(event.targetTouches);
  this.changedTouches = DvtSvgTouchEvent.createTouchArray(event.changedTouches);
  this._context = context;
  this._touchManager = null;
}

DvtSvgTouchEvent.prototype.blockTouchHold = function() {
  this._event._touchHoldBlocked = true;
}

DvtSvgTouchEvent.prototype.isInitialTouch = function() {
   return (this.touches.length - this.changedTouches.length) == 0;
}

DvtSvgTouchEvent.prototype.isTouchHoldBlocked = function() {
  return (this._event._touchHoldBlocked) ? true : false;
}

DvtSvgTouchEvent.createTouchArray = function(nativeTouchArray) {
  var touches = new Array();
  for (var i=0; i<nativeTouchArray.length; i++) {
      var nativeTouch = nativeTouchArray[i];
      var touch = new DvtTouch(nativeTouch);
      touches.push(touch);
  }
  return touches;
}

/**
 * Prevents further propagation of the current event
 */
DvtSvgTouchEvent.prototype.stopPropagation = function() {
    DvtSvgTouchEvent.superclass.stopPropagation.call(this);
    if (this._touchManager)
      this._touchManager.postEventBubble(this);
}

/**
 * Sets a touch manager object
 * @param {DvtTouchManager} touch manager object for the event
 */
DvtSvgTouchEvent.prototype.setTouchManager = function (touchManager) {
  this._touchManager = touchManager;
}
// Used for rendering SVG content in to an HTML div wrapper
/**
 * @param {DvtContext} context
 * @param {string} domElementId
 * @constructor
 */
var DvtHtmlRichTooltipManager = function(context, domElementId) {
    this.Init(context, domElementId);
};

DvtObj.createSubclass(DvtHtmlRichTooltipManager, DvtHtmlTooltipManager, "DvtHtmlRichTooltipManager");

/**
 * @param {DvtContext} context
 * @param {string} domElementId
 */
DvtHtmlRichTooltipManager.prototype.Init = function(context, domElementId) 
{
  this._storedContexts = new Object();
  DvtHtmlRichTooltipManager.superclass.Init.call(this, context, domElementId);
}

DvtHtmlRichTooltipManager.prototype.InitContent = function(tooltip) {
      var svg = DvtSvgUtils.createSvgDocument("DvtCustomTooltip");
      // For an svg custom tooltip, the context is the new svg context for the svg document overlay.
      var context = new DvtSvgContext(svg, 'tooltipStage');
      this._storedContexts[this._domElementId] = context;
      tooltip.innerHTML = "";
      DvtSvgUtils.appendChildElem(tooltip, svg);
}

DvtHtmlRichTooltipManager.prototype.GetStoredContext = function() {
    return this._storedContexts[this._domElementId];
}

DvtHtmlRichTooltipManager.prototype.showRichElement = function(x, y, renderable, useOffset)
{
    this.showRichElementAtPosition(x, y, renderable, useOffset, false, DvtHtmlTooltipManager.UNSTYLED_POPUP_CLASS);
};

DvtHtmlRichTooltipManager.prototype.showRichElementAtPosition = function(x, y, renderable, useOffset, noEvents, popupClass) {

    var tooltip = this.GetTooltipElem();
    
    if (!popupClass)
      popupClass = DvtHtmlTooltipManager.UNSTYLED_POPUP_CLASS;
      
    tooltip.className = popupClass;
    
    var context = this.GetStoredContext();
    if (context){
      var stage = context.getStage();
      stage.removeChildren();
      var rootDisplayable = renderable.getRootDisplayable();
      stage.addChild(rootDisplayable);
      
      if (renderable && renderable.Render) {
          renderable.Render();
      }
      
      var svg = stage.getImpl().getSVGRoot();
      DvtSvgUtils.setAttrNullNS(svg, "width", renderable.getDisplayWidth());
      DvtSvgUtils.setAttrNullNS(svg, "height", renderable.getDisplayHeight());
      
      this.PostElement(tooltip, x, y, noEvents, useOffset);
    }
}

DvtHtmlRichTooltipManager.prototype.hideTooltip = function()
{
    DvtHtmlRichTooltipManager.superclass.hideTooltip.call(this);
    var context = this.GetStoredContext();
    if (context) {
        var stage = context.getStage();
        stage.removeChildren();
    }
}
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.

/*---------------------------------------------------------------------*/
/*   DvtSvgImplFactory                                                 */
/*---------------------------------------------------------------------*/
/**
  * A factory class for SVG to create object implementations.
  * @extends  DvtHtmlImplFactory
  * @class DvtSvgImplFactory  A factory class to create SVG implementation objects.
  * @constructor  Creates SVG inplementation objects.
  */
var DvtSvgImplFactory = function(context) {
  this.Init(context) ;
};

DvtObj.createSubclass(DvtSvgImplFactory, DvtHtmlImplFactory, "DvtSvgImplFactory");

/*---------------------------------------------------------------------*/
/*     Base implementations                                            */
/*---------------------------------------------------------------------*/

/**
 *  Returns a new SVG <defs> element
 *  @private  
 */
DvtSvgImplFactory.prototype.newDefs = function() {
  return  DvtSvgShapeUtils.createElement('defs') ;
};

/**
 *  Returns a new DvtStage implementation object.
 */
DvtSvgImplFactory.prototype.newStage = function(root, id) {
  return  new DvtSvgStage(root, id) ;
};


/**
 * Returns a new DvtSvgContainer implementation.
 * @param {String} id  Optional ID for the object (see also {@link DvtDisplayable#setId}) 
 * @override
 * @type DvtContainer
 */
DvtSvgImplFactory.prototype.newContainer = function (id) {
  return new DvtSvgContainer(id, 'g');
};

/**
  *  Returns a new DvtSvgArc implementation object for an arc of a circle or ellipse.
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} rx  The horizontal radius of the ellipse/circle.
  *  @param {number} ry  The vertical radius of the ellipse/circle.
  *  @param {number} sa  The starting angle in degrees (following the normal anti-clockwise is positive convention).
  *  @param {number} ae  The angle extent in degrees (following the normal anti-clockwise is positive convention).
  *  @param {String} clos  An optional closure type for the arc. Closures are "OPEN" (the default), "SEGMENT", and "CHORD".
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *  @returns {DvtSvgArc}  A new {@link DvtArc} object.
 *   @override
 */
DvtSvgImplFactory.prototype.newArc = function (cx, cy, rx, ry, sa, ae, clos, id) {
  return new DvtSvgArc(cx, cy, rx, ry, sa, ae, clos, id);
};


/**
  *  Creates a new DvtSvgCircle implementation for a circle.
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} r   The radius of the circle.
  *  @param {String} id  Optional ID for the object (see also {@link DvtDisplayable#setId}) 
  *  <p>
  *  <b>Example:</b><br><br> The following code creates a red circle of radius 100
  *  and line width 5, centered at (10,10).
  *  <br><br><code>
  *  var circle = factory.newCircle(10, 10, 100, 'myCircle') ;<br>
  *  circle.setStroke(new DvtStroke("red", 5)) ;<br>
  *  </code><br>
  *  @returns {DvtSvgCircle} A new DvtSvgCircle object.
  *  @override
 */
DvtSvgImplFactory.prototype.newCircle = function (cx, cy, r, id) {
  return  new DvtSvgCircle(cx, cy, r, id);
};

/**
 *  Returns a new DvtSvgImage implementation object for a displayable image.
 *  @param {String} imgSrc  The image URL.
 *  @param {number} x  The x position of the top left corner of the image.
 *  @param {number} y  The y position of the top left corner of the image.
 *  @param {number} w  The width of the image (optional).
 *  @param {number} h  The height of the image (optional).
 *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 *  <p>
 *  Example:<br><br><code>
 *  var img = factory.newImage('pic.png', 10, 10, 100, 150, 'myImg') ;<br>
 *  </code>
 *  @returns  {@link DvtImage}  A new DvtSvgImage object.
 *  @override
 */
DvtSvgImplFactory.prototype.newImage = function (imgSrc, x, y, w, h, id) {
  return new DvtSvgImage(imgSrc, x, y, w, h, id);
};

/**
  *  Creates a new DvtSvgLine implementation object which for a displayable line
  *  segment drawn from (x1, y1) to (x2, y2).
  *  @param {number} x1  An x end position of the line.
  *  @param {number} y1  The associated y end point (for x1).
  *  @param {number} x2  The other x end point.
  *  @param {number} y2  The associated y end point (for x2).
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *  <p>Example:<br><br><code>
  *  var line = factory.newLine(10, 10, 100, 150);</code><br>
  *  @returns  {DvtSvgLine}  A new DvtSvgLine object.
  *  @override
  */
DvtSvgImplFactory.prototype.newLine = function (x1, y1, x2, y2, id) {
  return  new DvtSvgLine(x1, y1, x2, y2, id);
};


/**
 *  Returns a new DvtSvgMarker implementation object for a graph or legend marker.
 *  @param {number} type The type of the marker (see {@link DvtMarker}).
 *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 *  @param {String} etype  Optional element type for the shape (see {@link  DvtMarker}).
 *  <p>
 *  Example:<br><br><code>
 *  var rect = factory.newMarker(type, 'myRect') ;<br>
 *  </code>
 *  @returns {DvtSvgMarker}  A new DvtSvgMarker object.
 *  @override
 */
DvtSvgImplFactory.prototype.newMarker = function (type, id, etype) {
    return  new DvtSvgMarker(type, id, etype);
};


/**
  *  Returns a new DvtSvgOval implementation object which for a displayable ellipse.
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} rx  The horizontal radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *  @returns  {DvtSvgOval}  A new DvtSvgOval object.
 * @override
 */
DvtSvgImplFactory.prototype.newOval = function (cx, cy, rx, ry, id) {
  return  new DvtSvgOval(cx, cy, rx, ry, id);
};

/**
  * Returns a new DvtSvgPath implementation object for a displayable shape
  * defined by SVG path commands.
  * @param {Object} cmds  Optional string of SVG path commands (see comment for
  *                       {@link DvtPath#setCmds}), or an array containing
  *                       consecutive command and coordinate entries (see comment
  *                       for {@link DvtPath#setCommands}).
  * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  * @returns {DvtSvgPath}  A new DvtSvgPath object.
  * @override
 */
DvtSvgImplFactory.prototype.newPath = function (cmds, id) {
  return  new DvtSvgPath(cmds, id);
};

/**
 * Returns a new DvtSvgPolygon implementation object for a displayable shape composed of 
 * connected multi-line segments.
 * @param {array} ar  An array of consecutive x,y coordinate pairs.
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 * @returns {DvtSvgPolygon}  A new DvtSvgPolygon object.
 * @override
 */
DvtSvgImplFactory.prototype.newPolygon = function (arPoints, id) {
  return  new DvtSvgPolygon(arPoints, id);
};


/**
 *  Returns a new DvtSvgPolyline object for a line composed of multiple line segments.
 *  @param {array} ar  An array of consecutive x,y coordinate pairs.
 *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 *  @return {DvtSvgPolyline}  A new  DvtSvgPolyline object.
 *  @override
 */
DvtSvgImplFactory.prototype.newPolyline = function (ar, id) {
  return  new DvtSvgPolyline(ar, id);
};

/**
 *  Returns a new DvtSvgRect implementation object for a displayable rectangle.
 *  @param {number} x  The x position of the top left corner of the rectangle.
 *  @param {number} y  The y position of the top left corner of the rectangle.
 *  @param {number} w  The width of the rectangle.
 *  @param {number} h  The height of the rectangle.
 *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 *  <p>
 *  Example:<br><br><code>
 *  var rect = factory.newRect(10, 10, 100, 150, 'myRect') ;<br>
 *  </code>
 *  @returns {DvtSvgRect} A new DvtSvgRect object.
 *  @override
 */
DvtSvgImplFactory.prototype.newRect = function (x, y, w, h, id) {
  return  new DvtSvgRect(x, y, w, h, id);
};

/**
 * Returns a new DvtSvgText implementation object for displayable text.
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 * @returns {DvtSvgText}  A new DvtSvgText object.
 * @override
 */
DvtSvgImplFactory.prototype.newText = function (textStr, x, y, id) {
  return  new DvtSvgText(this.GetContext(), textStr, x, y, id);
};

/**
 * Returns a new DvtSvgTextArea implementation object for displayable text.
 * @param x {number} x the x position
 * @param y {number} y the y position
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 * @returns {DvtSvgTextArea}   A new DvtSvgTextArea object.
 * @override
 */
DvtSvgImplFactory.prototype.newTextArea = function (x, y, id) {
  return new DvtSvgTextArea(this.GetContext(), x, y, id);
};


/**
 * Returns a new DvtSvgTextFormatted implementation object for displayable text.
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 * @returns {DvtSvgTextFormatted}  A new DvtSvgTextFormatted object.
 * @type DvtTextFormatted
 * @override
 */
DvtSvgImplFactory.prototype.newTextFormatted = function (x, y, id) {
  return  new DvtSvgTextFormatted(this.GetContext(), x, y, id);
};

/**
 * Obtain imageLoader singleton
 * @override
 */
DvtSvgImplFactory.prototype.getImageLoader = function () {
  if (DvtAgent.isEnvironmentBrowser())
    return DvtSvgImageLoader;
  else
    return DvtJavaImageLoader;
};

/**
 * @override
 */
DvtSvgImplFactory.prototype.getDocumentUtils = function () {
  return DvtSvgDocumentUtils;
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*   DvtSvgJsExt            SVG implementation of DvtJsExt             */
/*---------------------------------------------------------------------*/


//  Placeholder - revist if/when callbacks are used.


/**
  *  Provides a gateway for access to ADF functionality for SVG. 
  *  @class DvtSvgJsExt
  *  @extends DvtJsExt
  *  @constructor
  */
var  DvtSvgJsExt = function()
{
};

DvtObj.createSubclass(DvtSvgJsExt, DvtJsExt, "DvtSvgJsExt");



/*---------------------------------------------------------------------*/
/*                                 ADF                                 */
/*---------------------------------------------------------------------*/
/**  
  *  Sets a PPR property value.
  *  @param {String}  id  An id to be substituted in the function call.
  *  @param {String)  prop a property such as {@link DvtJsExt#PPR_ATTRIB_HSS}
  *  @param {String}  value  the property value.
  */
DvtSvgJsExt.prototype.sendPPRProperty = function(id, prop, value)
{
/*
    var fun = DvtJsExt.JS_FP_SET_PPR_PROPERTY.replace("X-ID-X", id);
    fun = fun.replace("X-ID-X", id);
    var js  = fun + "('" + prop + "','" + value + "')";
    eval(js) ;
*/

  try {
         AdfPage.PAGE.findComponent(id).getPeer().setDVTPPRAttribute(prop,value) ;
  }
  catch (err) {} 
};


/**
  *   @param {String} id
  */
DvtSvgJsExt.prototype.sendPPR  = function(id)
{
/*
    var js  =  DvtJsExt.JS_FP_SEND.replace("X-ID-X", id) ;
    js = js.replace("X-ID-X", id) ;
    eval(js) ;
*/

  try {
    AdfPage.PAGE.findComponent(id).getPeer().sendToServerPPR({source:id}) ;
  }
  catch (err) {} 
};

/**
  *   @param {String} id
  */
DvtSvgJsExt.prototype.sendPPRNonBlocking = function(id)
{
/*
    var js  =  DvtJsExt.JS_FP_SEND_PPR_NON_BLOCKING.replace("X-ID-X", id) ;
    js = js.replace("X-ID-X", id) ;
    eval(js) ;
*/

  try {
        AdfPage.PAGE.findComponent(id).getPeer().sendToServerPPR3({source:id}) ;
  }
  catch (err) {} 
};



/*---------------------------------------------------------------------*/
/*                    External Javascript invocation                   */
/*---------------------------------------------------------------------*/

/**
  *   Performs the specified Javascript.
  *   @returns {unknown} the result, if any, of the Javascript execution.
  */
DvtSvgJsExt.prototype.callJs = function(js)
{
   //BUG 34184877 - MAKE DVT COMPATIBLE WITH CSP STANDARDS
   var jsArray = js.match(/'(.*?)'/g);
   var src= jsArray[0].replace(/\'/g, "");
   var eventData= jsArray[2].replace(/\'/g, "");
   var biData= jsArray[3].replace(/\'/g, "");
   return AdfPage.PAGE.findComponent(src).getPeer().sendToServerPPR({source:src,event:eventData,bi_gdzA:biData});
};

/**
  *   Performs the specified Javascript.
  *   @param {String} js the js function to call
  *   @param {unknown} param the param to pass to the function
  *   @returns {unknown} the result, if any, of Javascript.
  */
DvtSvgJsExt.prototype.callJsWithParam = function(js, param)
{
  var func = eval(js);
  return func(param);
};


/*---------------------------------------------------------------------*/
/*                            Logging                                  */
/*---------------------------------------------------------------------*/

/**
  *   Returns the current ADF log level.
  *   @returns {number} the current ADF log level (such as {DvtJsExt#LOG_WARNING}).
  */
DvtSvgJsExt.prototype.getLogLevel = function()
{
    return  adf_dvt_fpGetLogLevel() ;
};


/**
  *   Forwards a message to the ADF logger.
  *   @param  {String} msg the message to be logged.
  *   @param  {number} level the log level of the messsage.  If omitted
  *                          a value of {DvtJsExt#LOG_INFO} is assumed.
  */
DvtSvgJsExt.prototype.log = function(msg, level)
{
    adf_dvt_fpLogger(msg, (level === undefined? DvtJsExt.LOG_INFO : level)) ;
};


/**
  *   Forwards a message string to ADF DVT.
  *   @param  {String} msg the message to be sent.
  */
DvtSvgJsExt.prototype.msg = function(msg)
{
    adf_dvt_fpMsg(msg) ;
};



/*---------------------------------------------------------------------*/
/*                           Performance                               */
/*---------------------------------------------------------------------*/

/**
  *   Forwards a performance message.
  *   @param  {String} msg the performance message to be sent.
  *   @param  {number} type  the performance type (such as {DvtJsExt#PERF_TIMING}).
  */

DvtSvgJsExt.prototype.perf = function(s, type)
{
    adf_dvt_fpPerfLogger('' + type + s) ;     // Due to original issues with args in
                                              // Flash the type is currently sent at
                                              // the start of the string.
};



/*---------------------------------------------------------------------*/
/*                            Miscellaneous                            */
/*---------------------------------------------------------------------*/

/**
  *        TDO - JRM  is this still needed ?
  */
DvtSvgJsExt.prototype.requestRefresh = function()
{
    adf_dvt_fpRefresh() ;
};


DvtSvgJsExt.prototype.dispatchEvent = function(callback, callbackObj, component, event) {
  DvtEventDispatcher.dispatchEvent(callback, callbackObj, component, event);
}
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.
/**
 * @constructor
 */
var DvtSvgFilterContext = function()
{
  this.Init();
};

DvtObj.createSubclass(DvtSvgFilterContext, DvtObj, "DvtSvgFilterContext");

DvtSvgFilterContext.prototype.Init = function()
{
  this._regionPctRect = new DvtRectangle(-10, -10, 120, 120);
  this._counter = 0;
  this._resultIdsUnder = [];
  this._resultIdsOver = [];
};

DvtSvgFilterContext.prototype.getRegionPctRect = function()
{
  return this._regionPctRect;
};

DvtSvgFilterContext.prototype.getResultIdsUnder = function()
{
  return this._resultIdsUnder;
};

DvtSvgFilterContext.prototype.getResultIdsOver = function()
{
  return this._resultIdsOver;
};

DvtSvgFilterContext.prototype.createResultId = function(id)
{
  if (!id)
  {
    id = "filtRes";
  }
  return (id + (this._counter++));
};
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.

/**
  *   Static SVG filter routines.
  *   @class DvtSvgFilterUtils 
  *   @constructor
  */
var  DvtSvgFilterUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgFilterUtils, DvtObj, "DvtSvgFilterUtils");

DvtSvgFilterUtils._counter = 0;

DvtSvgFilterUtils.createFilter = function(effects, svgDisplayable)
{
  var filt = DvtSvgShapeUtils.createElement('filter', DvtSvgFilterUtils.CreateFilterId());
  var filtContext = new DvtSvgFilterContext();
  for (var i = 0; i < effects.length; i++)
  {
    var effect = effects[i];
    if (effect)
    {
      DvtSvgFilterUtils.CreateFilterPrimitives(filt, effect, svgDisplayable, filtContext);
    }
  }
  
  // BUG #12805402: When bounding box of svg element has zero height or width, userSpaceOnUse must be used
  // Otherwise, the element will disappear
  var userSpaceOnUse = false;
  if (svgDisplayable) {
      var obj = svgDisplayable.getObj();
      var boundsRect;
      if (obj && obj._bInitFx && obj._origRect)
        boundsRect = obj._origRect;
      else
        boundsRect = svgDisplayable.getElem().getBBox();
      if (boundsRect) {
          var width = boundsRect.width;
          var height = boundsRect.height;
          if (height == 0 || width == 0) {
            var stroke;
            //if displayable is not a shape, for example a container, then it doesn't have a stroke
            if (svgDisplayable.getStroke) {
              stroke = svgDisplayable.getStroke();
            }
            var adjustWidth = 10;
            if (stroke) {
                adjustWidth = stroke.getWidth();
            }
            var x = boundsRect.x;
            var y = boundsRect.y;
    
            // Firefox 4 requires the line to be bend slightly when feColorMatrix is used
            if (DvtSvgDocumentUtils.isFilterStraightLineAdjustmentNeeded()) {
                if (svgDisplayable instanceof DvtSvgPolyline) {
                   var points = DvtArrayUtils.copy(svgDisplayable.getPoints());
                   if (width == 0) {
                       points[0] = points[0]+0.01;
                   }
                   if (height == 0) {
                       points[1] = points[1]+0.01;
                   }
        
                   var bentPoints = DvtSvgShapeUtils.convertPointsArray(points);
                   DvtSvgUtils.setAttrNullNS(svgDisplayable.getElem(), 'points', bentPoints) ;
                }
            }
    
            if (height == 0) {
                height = 2*adjustWidth;
                y -= adjustWidth;
            }
            if (width == 0) {
                width = 2*adjustWidth;
                x -= adjustWidth;
            }
    
            DvtSvgUtils.setAttrNullNS(filt, 'x', x) ;
            DvtSvgUtils.setAttrNullNS(filt, 'y', y) ;
            DvtSvgUtils.setAttrNullNS(filt, 'width', width) ;
            DvtSvgUtils.setAttrNullNS(filt, 'height', height) ;
            DvtSvgUtils.setAttrNullNS(filt, 'filterUnits', 'userSpaceOnUse') ;
            userSpaceOnUse = true;
          }
      }
  }
  if (!userSpaceOnUse) {
      if (filtContext.getRegionPctRect().x != -10 && filtContext.getRegionPctRect().x != "Infinity" && filtContext.getRegionPctRect().x != "-Infinity")
      {
        DvtSvgUtils.setAttrNullNS(filt, 'x', filtContext.getRegionPctRect().x + '%') ;
      }
      if (filtContext.getRegionPctRect().y != -10 && filtContext.getRegionPctRect().y != "Infinity" && filtContext.getRegionPctRect().y != "-Infinity")
      {
        DvtSvgUtils.setAttrNullNS(filt, 'y', filtContext.getRegionPctRect().y + '%') ;
      }
      if (filtContext.getRegionPctRect().w != 120 && filtContext.getRegionPctRect().w != "Infinity" && filtContext.getRegionPctRect().w != "-Infinity")
      {
        DvtSvgUtils.setAttrNullNS(filt, 'width', filtContext.getRegionPctRect().w + '%') ;
      }
      if (filtContext.getRegionPctRect().h != 120 && filtContext.getRegionPctRect().h != "Infinity" && filtContext.getRegionPctRect().h != "-Infinity")
      {
        DvtSvgUtils.setAttrNullNS(filt, 'height', filtContext.getRegionPctRect().h + '%') ;
      }
        
  }

  
  var numResultsUnder = filtContext.getResultIdsUnder().length;
  var numResultsOver = filtContext.getResultIdsOver().length;
  var elemMN;
  var j;
  
  var elemM  = DvtSvgShapeUtils.createElement('feMerge') ;
  if (numResultsUnder > 0)
  {
    for (j = 0; j < numResultsUnder; j++)
    {
      elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
      DvtSvgUtils.setAttrNullNS(elemMN, 'in', filtContext.getResultIdsUnder()[j]) ;
      DvtSvgUtils.appendChildElem(elemM, elemMN) ;
    }
  }
  elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
  DvtSvgUtils.setAttrNullNS(elemMN, 'in', 'SourceGraphic') ;
  DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  if (numResultsOver > 0)
  {
    for (j = 0; j < numResultsOver; j++)
    {
      elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
      DvtSvgUtils.setAttrNullNS(elemMN, 'in', filtContext.getResultIdsOver()[j]) ;
      DvtSvgUtils.appendChildElem(elemM, elemMN) ;
    }
  }
  DvtSvgUtils.appendChildElem(filt, elemM) ;
  
  return filt;
};

DvtSvgFilterUtils.CreateFilterPrimitives = function(filter, effect, svgDisplayable, filtContext)
{
  if (effect instanceof DvtShadow)
  {
    DvtSvgShadowUtils.createFilterPrimitives(filter, effect, svgDisplayable, filtContext);
  }
  else if (effect instanceof DvtGlow)
  {
    DvtSvgGlowUtils.createFilterPrimitives(filter, effect, svgDisplayable, filtContext);
  }
  else if (effect instanceof DvtBevel)
  {
    DvtSvgBevelUtils.createFilterPrimitives(filter, effect, svgDisplayable, filtContext);
  }
  
  return null;
};

DvtSvgFilterUtils.CreateFilterId = function()
{
  return ("filt" + (DvtSvgFilterUtils._counter++));
};
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------------*/
/*   DvtSvgBevelUtils    A static class for SVG bevel effect property        */
/*                      manipulation.                                        */
/*---------------------------------------------------------------------------*/
/**
  *   DvtSvgBevelUtils    A static class for SVG bevel effect property manipulation.
  *   @class DvtSvgBevelUtils 
  *   @constructor
  */
var  DvtSvgBevelUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgBevelUtils, DvtObj, "DvtSvgBevelUtils");

/**
  *  Static method to create an SVG filter element and apply bevel properties to it.
  *  @param {Dvtbevel}  bevel  Dvtbevel object
  *  @param {DvtSvgDisplayable}  svgDisplayable  display object to apply bevel to
  *  @returns an SVG  &lt;filter&gt; element
  */
DvtSvgBevelUtils.createFilter = function(bevel, svgDisplayable)
{
   //  The following outer bevel filter is created:
   
   
   //   The following inner bevel filter is created:
   
   
   var filt = DvtSvgBevelUtils.CreateFilterElem(bevel);
   var filtContext = new DvtSvgFilterContext();
   
   DvtSvgBevelUtils.createFilterPrimitives(filt, bevel, svgDisplayable, filtContext);
   
  var elemM  = DvtSvgShapeUtils.createElement('feMerge') ;
  var elemMN;
  if (filtContext.getResultIdsUnder().length > 0)
  {
    elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
    DvtSvgUtils.setAttrNullNS(elemMN, 'in', filtContext.getResultIdsUnder()[0]) ;
    DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  }
  elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
  DvtSvgUtils.setAttrNullNS(elemMN, 'in', 'SourceGraphic') ;
  DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  if (filtContext.getResultIdsOver().length > 0)
  {
    elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
    DvtSvgUtils.setAttrNullNS(elemMN, 'in', filtContext.getResultIdsOver()[0]) ;
    DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  }
  DvtSvgUtils.appendChildElem(filt, elemM) ;
  
  if (filtContext.getRegionPctRect().x != -10)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'x', filtContext.getRegionPctRect().x + '%') ;
  }
  if (filtContext.getRegionPctRect().y != -10)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'y', filtContext.getRegionPctRect().y + '%') ;
  }
  if (filtContext.getRegionPctRect().w != 120)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'width', filtContext.getRegionPctRect().w + '%') ;
  }
  if (filtContext.getRegionPctRect().h != 120)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'height', filtContext.getRegionPctRect().h + '%') ;
  }
   
   return filt;
};

DvtSvgBevelUtils.createFilterPrimitives = function(filt, effect, svgDisplayable, filtContext)
{
  if (effect._type === DvtBevel.TYPE_INNER)
  {
    var boundsRect = svgDisplayable.getDimensions(svgDisplayable.getParent());
    DvtSvgBevelUtils.CreateInnerFilterPrimitives2(filt, effect, filtContext, boundsRect);
  }
  else if (effect._type === DvtBevel.TYPE_OUTER)
  {
    //TODO
  }
  else if (effect._type === DvtBevel.TYPE_FULL)
  {
    //TODO
  }
};

/**
  * @protected
  */
DvtSvgBevelUtils.CreateFilterElem = function(bevel)
{
  var filt = DvtSvgShapeUtils.createElement('filter', bevel._Id) ;
  return filt;
};

/**
  * @protected
  */
/*DvtSvgBevelUtils.CreateInnerFilterPrimitives = function(filt, bevel, filtContext)
{
  //var distance = bevel._distance;
  var angle = bevel._angle;
  var hilightRed   = DvtColorUtils.getRed(bevel._hilightRgba) ;
  var hilightGreen = DvtColorUtils.getGreen(bevel._hilightRgba) ;
  var hilightBlue  = DvtColorUtils.getBlue(bevel._hilightRgba) ;
  var hilightAlpha = DvtColorUtils.getAlpha(bevel._hilightRgba) ;
  //var hilightRgb = DvtColorUtils.makeRGB(hilightRed, hilightGreen, hilightBlue);
  var shadowRed   = DvtColorUtils.getRed(bevel._shadowRgba) ;
  var shadowGreen = DvtColorUtils.getGreen(bevel._shadowRgba) ;
  var shadowBlue  = DvtColorUtils.getBlue(bevel._shadowRgba) ;
  var shadowAlpha = DvtColorUtils.getAlpha(bevel._shadowRgba) ;
  //var shadowRgb = DvtColorUtils.makeRGB(shadowRed, shadowGreen, shadowBlue);
  //var strength = bevel._strength;
  var blurX = bevel._blurX;
  var blurY = bevel._blurY;
  
  //create bump map for specular lighting
  var elemGB = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'in', 'SourceAlpha') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', blurX + " " + blurY) ;
  var elemGBResult = filtContext.createResultId('blur');
  DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;
  
  //specular highlight
  var elemSL = DvtSvgShapeUtils.createElement('feSpecularLighting') ;
  DvtSvgUtils.setAttrNullNS(elemSL, 'in', elemGBResult) ;
  DvtSvgUtils.setAttrNullNS(elemSL, 'surfaceScale', 5) ;
  DvtSvgUtils.setAttrNullNS(elemSL, 'specularConstant', 1) ;//.85);
  DvtSvgUtils.setAttrNullNS(elemSL, 'specularExponent', 20) ;
  //use pure white, and later convert to specified color
  DvtSvgUtils.setAttrNullNS(elemSL, 'lighting-color', '#ffffff');//hilightRgb) ;
  var elemSLResult = filtContext.createResultId('specLight');
  DvtSvgUtils.setAttrNullNS(elemSL, 'result', elemSLResult) ;
  
  var elemDL = DvtSvgShapeUtils.createElement('feDistantLight') ;
  DvtSvgUtils.setAttrNullNS(elemDL, 'azimuth', -angle) ;
  //elemDL , 'elevation', 0) ;
  
  //only keep part of specular highlight within original shape
  var elemC1 = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'operator', 'in') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in', elemSLResult) ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in2', 'SourceAlpha') ;
  var elemC1Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC1, 'result', elemC1Result) ;

  //convert white specular hilight to correct color
  var elemCM = DvtSvgShapeUtils.createElement('feColorMatrix') ;
  DvtSvgUtils.setAttrNullNS(elemCM, 'in', elemC1Result) ;
  DvtSvgUtils.setAttrNullNS(elemCM, 'type', 'matrix') ;
  DvtSvgUtils.setAttrNullNS(elemCM, 'values', (hilightRed/255) + ' 0 0 0 0 ' +
                                       '0 ' + (hilightGreen/255) + ' 0 0 0 ' +
                                       '0 0 ' + (hilightBlue/255) + ' 0 0 ' +
                                       //'0 0 0 ' + hilightAlpha + ' 0') ;
                                       '0 0 0 1 0') ;
  var elemCMResult = filtContext.createResultId('colMat');
  DvtSvgUtils.setAttrNullNS(elemCM, 'result', elemCMResult) ;
  
  //specular shadow
  var elemSL2 = DvtSvgShapeUtils.createElement('feSpecularLighting') ;
  DvtSvgUtils.setAttrNullNS(elemSL2, 'in', elemGBResult) ;
  DvtSvgUtils.setAttrNullNS(elemSL2, 'surfaceScale', 5) ;
  DvtSvgUtils.setAttrNullNS(elemSL2, 'specularConstant', 1) ;//.85);
  DvtSvgUtils.setAttrNullNS(elemSL2, 'specularExponent', 20) ;
  //use pure white, and later convert to specified color
  DvtSvgUtils.setAttrNullNS(elemSL2, 'lighting-color', '#ffffff');//shadowRgb) ;
  var elemSL2Result = filtContext.createResultId('specLight');
  DvtSvgUtils.setAttrNullNS(elemSL2, 'result', elemSL2Result) ;
  
  var elemDL2 = DvtSvgShapeUtils.createElement('feDistantLight') ;
  DvtSvgUtils.setAttrNullNS(elemDL2, 'azimuth', -(angle + 180)) ;
  //DvtSvgUtils.setAttrNullNS(elemDL2, 'elevation', 0) ;
  
  //only keep part of specular shadow within original shape
  var elemC2 = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC2, 'operator', 'in') ;
  DvtSvgUtils.setAttrNullNS(elemC2, 'in', elemSL2Result) ;
  DvtSvgUtils.setAttrNullNS(elemC2, 'in2', 'SourceAlpha') ;
  var elemC2Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC2, 'result', elemC2Result) ;

  //convert white specular hilight to correct color
  var elemCM2 = DvtSvgShapeUtils.createElement('feColorMatrix') ;
  DvtSvgUtils.setAttrNullNS(elemCM2, 'in', elemC2Result) ;
  DvtSvgUtils.setAttrNullNS(elemCM2, 'type', 'matrix') ;
  DvtSvgUtils.setAttrNullNS(elemCM2, 'values', (shadowRed/255) + ' 0 0 0 0 ' +
                                        '0 ' + (shadowGreen/255) + ' 0 0 0 ' +
                                        '0 0 ' + (shadowBlue/255) + ' 0 0 ' +
                                        //'0 0 0 ' + shadowAlpha + ' 0') ;
                                        '0 0 0 1 0') ;
  var elemCM2Result = filtContext.createResultId('colMat');
  DvtSvgUtils.setAttrNullNS(elemCM2, 'result', elemCM2Result) ;
  
  filtContext.getResultIdsOver().push(elemCMResult);
  filtContext.getResultIdsOver().push(elemCM2Result);
  
  DvtSvgUtils.appendChildElem(filt, elemGB) ;
  DvtSvgUtils.appendChildElem(filt, elemSL) ;
  DvtSvgUtils.appendChildElem(elemSL, elemDL) ;
  DvtSvgUtils.appendChildElem(filt, elemC1) ;
  DvtSvgUtils.appendChildElem(filt, elemCM);
  DvtSvgUtils.appendChildElem(filt, elemSL2) ;
  DvtSvgUtils.appendChildElem(elemSL2, elemDL2) ;
  DvtSvgUtils.appendChildElem(filt, elemC2) ;
  DvtSvgUtils.appendChildElem(filt, elemCM2);
};*/

/**
  * @protected
  */
DvtSvgBevelUtils.CreateInnerFilterPrimitives2 = function(filt, bevel, filtContext, boundsRect)
{
  var distance = bevel._distance;
  var angle = bevel._angle;
  var hilightRed   = DvtColorUtils.getRed(bevel._hilightRgba) ;
  var hilightGreen = DvtColorUtils.getGreen(bevel._hilightRgba) ;
  var hilightBlue  = DvtColorUtils.getBlue(bevel._hilightRgba) ;
  var hilightAlpha = DvtColorUtils.getAlpha(bevel._hilightRgba) ;
  var hilightRgb = DvtColorUtils.makeRGB(hilightRed, hilightGreen, hilightBlue);
  var shadowRed   = DvtColorUtils.getRed(bevel._shadowRgba) ;
  var shadowGreen = DvtColorUtils.getGreen(bevel._shadowRgba) ;
  var shadowBlue  = DvtColorUtils.getBlue(bevel._shadowRgba) ;
  var shadowAlpha = DvtColorUtils.getAlpha(bevel._shadowRgba) ;
  var shadowRgb = DvtColorUtils.makeRGB(shadowRed, shadowGreen, shadowBlue);
  //var strength = bevel._strength;
  var blurX = bevel._blurX * .5;
  var blurY = bevel._blurY * .5;
  
  //if we have a boundsRect, increase the size of the filter so
  //that the temporary outer glow has room to display outside the shape
  if (boundsRect)
  {
    var xRatio = (2 * blurX / boundsRect.w) * 100;
    var yRatio = (2 * blurY / boundsRect.h) * 100;
    if (filtContext.getRegionPctRect().x > -xRatio)
    {
      filtContext.getRegionPctRect().x = -xRatio;
    }
    if (filtContext.getRegionPctRect().y > -yRatio)
    {
      filtContext.getRegionPctRect().y = -yRatio;
    }
    if (filtContext.getRegionPctRect().w < (100 + 2 * xRatio))
    {
      filtContext.getRegionPctRect().w = (100 + 2 * xRatio);
    }
    if (filtContext.getRegionPctRect().h < (100 + 2 * yRatio))
    {
      filtContext.getRegionPctRect().h = (100 + 2 * yRatio);
    }
  }
  
  //create an outer glow on the shape
  var elemGB  = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'in', 'SourceAlpha') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', blurX + " " + blurY) ;
  var elemGBResult = filtContext.createResultId('blur');
  DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;
  
  //shift the outer glow to expose some of the original shape along
  //the edge we want to hilight
  var angleRads = angle * Math.PI / 180;
  var dx = distance * Math.cos(angleRads);
  var dy = distance * Math.sin(angleRads);
  var elemO = DvtSvgShapeUtils.createElement('feOffset') ;
  DvtSvgUtils.setAttrNullNS(elemO, 'dx', dx) ;
  DvtSvgUtils.setAttrNullNS(elemO, 'dy', dy) ;
  DvtSvgUtils.setAttrNullNS(elemO, 'in', elemGBResult) ;
  var elemOResult = filtContext.createResultId('offset');
  DvtSvgUtils.setAttrNullNS(elemO, 'result', elemOResult) ;
  
  //create a flood of the hilight color
  var elemF1 = DvtSvgShapeUtils.createElement('feFlood') ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'in', 'SourceAlpha') ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'flood-opacity', hilightAlpha / 3) ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'flood-color', hilightRgb) ;
  var elemF1Result = filtContext.createResultId('flood');
  DvtSvgUtils.setAttrNullNS(elemF1, 'result', elemF1Result) ;
  
  //keep the part of the flood outside the shifted glow
  var elemC1 = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'operator', 'out') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in', elemF1Result) ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in2', elemOResult) ;
  var elemC1Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC1, 'result', elemC1Result) ;
  
  //keep the part inside the original shape
  var elemC2 = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC2, 'operator', 'in');
  DvtSvgUtils.setAttrNullNS(elemC2, 'in', elemC1Result) ;
  DvtSvgUtils.setAttrNullNS(elemC2, 'in2', 'SourceGraphic') ;
  var elemC2Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC2, 'result', elemC2Result) ;
  
  //shift the outer glow to expose some of the original shape along
  //the edge we want to shadow
  var elemO2 = DvtSvgShapeUtils.createElement('feOffset') ;
  DvtSvgUtils.setAttrNullNS(elemO2, 'dx', -dx) ;
  DvtSvgUtils.setAttrNullNS(elemO2, 'dy', -dy) ;
  DvtSvgUtils.setAttrNullNS(elemO2, 'in', elemGBResult) ;
  var elemO2Result = filtContext.createResultId('offset');
  DvtSvgUtils.setAttrNullNS(elemO2, 'result', elemO2Result) ;
  
  //create a flood of the shadow color
  var elemF2 = DvtSvgShapeUtils.createElement('feFlood') ;
  DvtSvgUtils.setAttrNullNS(elemF2, 'in', 'SourceAlpha') ;
  DvtSvgUtils.setAttrNullNS(elemF2, 'flood-opacity', shadowAlpha * 2) ;
  DvtSvgUtils.setAttrNullNS(elemF2, 'flood-color', shadowRgb) ;
  var elemF2Result = filtContext.createResultId('flood');
  DvtSvgUtils.setAttrNullNS(elemF2, 'result', elemF2Result) ;
  
  //keep the part of the flood outside the shifted glow
  var elemC3 = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC3, 'operator', 'out') ;
  DvtSvgUtils.setAttrNullNS(elemC3, 'in', elemF2Result) ;
  DvtSvgUtils.setAttrNullNS(elemC3, 'in2', elemO2Result) ;
  var elemC3Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC3, 'result', elemC3Result) ;
  
  //keep the part inside the original shape
  var elemC4 = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC4, 'operator', 'in');
  DvtSvgUtils.setAttrNullNS(elemC4, 'in', elemC3Result) ;
  DvtSvgUtils.setAttrNullNS(elemC4, 'in2', 'SourceGraphic') ;
  var elemC4Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC4, 'result', elemC4Result) ;
  
  filtContext.getResultIdsOver().push(elemC2Result);
  filtContext.getResultIdsOver().push(elemC4Result);

  DvtSvgUtils.appendChildElem(filt, elemGB) ;
  DvtSvgUtils.appendChildElem(filt, elemO) ;
  DvtSvgUtils.appendChildElem(filt, elemF1) ;
  DvtSvgUtils.appendChildElem(filt, elemC1) ;
  DvtSvgUtils.appendChildElem(filt, elemC2) ;
  DvtSvgUtils.appendChildElem(filt, elemO2) ;
  DvtSvgUtils.appendChildElem(filt, elemF2) ;
  DvtSvgUtils.appendChildElem(filt, elemC3) ;
  DvtSvgUtils.appendChildElem(filt, elemC4) ;
};
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------------*/
/*   DvtSvgGlowUtils    A static class for SVG glow effect property          */
/*                      manipulation.                                        */
/*---------------------------------------------------------------------------*/
/**
  *   DvtSvgGlowUtils    A static class for SVG glow effect property manipulation.
  *   @class DvtSvgGlowUtils 
  *   @constructor
  */
var  DvtSvgGlowUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgGlowUtils, DvtObj, "DvtSvgGlowUtils");

/**
  *  Static method to create an SVG filter element and apply glow properties to it.
  *  @param {DvtGlow}  glow  DvtGlow object
  *  @param {DvtSvgDisplayable}  svgDisplayable  display object to apply glow to
  *  @returns an SVG  &lt;filter&gt; element
  */
DvtSvgGlowUtils.createFilter = function(glow, svgDisplayable)
{
   //  The following outer glow filter is created:

   //   <filter id="dg1">
   //     <feColorMatrix type="matrix" values="0 0 0 red 0
   //                                          0 0 0 green 0
   //                                          0 0 0 blue 0
   //                                          0 0 0 alpha 0"/>
   //     <feGaussianBlur stdDeviation="6 6" result="blur1"/>
   //     <feMerge>
   //       <feMergeNode in="blur1"/>
   //       <feMergeNode in="SourceGraphic"/>
   //     </feMerge>
   //   </filter>
   
   
   //   The following inner glow filter is created:
   
   //   <filter id="dg1">
   //     <feGaussianBlur stdDeviation="3" result="blur1"/>
   //     <feComposite operator="in" in="SourceGraphic" in2="blur1" result="comp1"/>
   //     <feComposite operator="in" in2="comp1" result="comp2"/>
   //     <feFlood in="comp2" flood-opacity="1" flood-color="rgb(255,255,255)" result="flood1"/>
   //     <feBlend mode="normal" in="comp2" in2="flood1" result="blend1"/>
   //     <feComposite operator="in" in="blend1" in2="SourceGraphic" result="comp3"/>
   //   </filter>
   
   var filt = DvtSvgGlowUtils.CreateFilterElem(glow);
   var filtContext = new DvtSvgFilterContext();
   
   DvtSvgGlowUtils.createFilterPrimitives(filt, glow, svgDisplayable, filtContext);
   
  var elemM  = DvtSvgShapeUtils.createElement('feMerge') ;
  var elemMN;
  if (filtContext.getResultIdsUnder().length > 0)
  {
    elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
    DvtSvgUtils.setAttrNullNS(elemMN, 'in', filtContext.getResultIdsUnder()[0]) ;
    DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  }
  elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
  DvtSvgUtils.setAttrNullNS(elemMN, 'in', 'SourceGraphic') ;
  DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  if (filtContext.getResultIdsOver().length > 0)
  {
    elemMN = DvtSvgShapeUtils.createElement('feMergeNode') ;
    DvtSvgUtils.setAttrNullNS(elemMN, 'in', filtContext.getResultIdsOver()[0]) ;
    DvtSvgUtils.appendChildElem(elemM, elemMN) ;
  }
  DvtSvgUtils.appendChildElem(filt, elemM) ;
   
   if (filtContext.getRegionPctRect().x != -10)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'x', filtContext.getRegionPctRect().x + '%') ;
  }
  if (filtContext.getRegionPctRect().y != -10)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'y', filtContext.getRegionPctRect().y + '%') ;
  }
  if (filtContext.getRegionPctRect().w != 120)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'width', filtContext.getRegionPctRect().w + '%') ;
  }
  if (filtContext.getRegionPctRect().h != 120)
  {
    DvtSvgUtils.setAttrNullNS(filt, 'height', filtContext.getRegionPctRect().h + '%') ;
  }
   
   return filt;
};

DvtSvgGlowUtils.createFilterPrimitives = function(filt, effect, svgDisplayable, filtContext)
{
  if (effect._bInner)
  {
    DvtSvgGlowUtils.CreateInnerFilterPrimitives2(filt, effect, filtContext);
  }
  else
  {
    var boundsRect = svgDisplayable.getDimensions(svgDisplayable.getParent());
    DvtSvgGlowUtils.CreateOuterFilterPrimitives(filt, effect, filtContext, boundsRect);
  }
};

/**
  * @protected
  */
DvtSvgGlowUtils.CreateFilterElem = function(glow)
{
  var filt = DvtSvgShapeUtils.createElement('filter', glow._Id) ;
  return filt;
};

/**
  * @protected
  */
DvtSvgGlowUtils.CreateOuterFilterPrimitives = function(filt, glow, filtContext, boundsRect)
{
  var rgba  = glow._rgba ;
  var red   = DvtColorUtils.getRed(rgba)/255 ;
  var green = DvtColorUtils.getGreen(rgba)/255 ;
  var blue  = DvtColorUtils.getBlue(rgba)/255 ;
  var alpha = DvtColorUtils.getAlpha(rgba) ;
  var strength = glow._strength;
  //adjust blur values so that SVG behaves more like Flash
  var blurX = glow._blurX / 3;
  var blurY = glow._blurY / 3;

  //if we have a boundsRect, increase the size of the filter so
  //that the glow has room to display outside the shape
  if (boundsRect)
  {
    var xRatio = (2 * blurX / boundsRect.w) * 100;
    var yRatio = (2 * blurY / boundsRect.h) * 100;
    if (filtContext.getRegionPctRect().x > -xRatio)
    {
      filtContext.getRegionPctRect().x = -xRatio;
    }
    if (filtContext.getRegionPctRect().y > -yRatio)
    {
      filtContext.getRegionPctRect().y = -yRatio;
    }
    if (filtContext.getRegionPctRect().w < (100 + 2 * xRatio))
    {
      filtContext.getRegionPctRect().w = (100 + 2 * xRatio);
    }
    if (filtContext.getRegionPctRect().h < (100 + 2 * yRatio))
    {
      filtContext.getRegionPctRect().h = (100 + 2 * yRatio);
    }
  }

  var elemCM  = DvtSvgShapeUtils.createElement('feColorMatrix') ;
  DvtSvgUtils.setAttrNullNS(elemCM, 'in', 'SourceGraphic') ;
  DvtSvgUtils.setAttrNullNS(elemCM, 'type', 'matrix') ;
  DvtSvgUtils.setAttrNullNS(elemCM, 'values', '0 0 0 ' + red   + ' 0 ' +
                                       '0 0 0 ' + green + ' 0 ' +
                                       '0 0 0 ' + blue  + ' 0 ' +
                                       '0 0 0 ' + alpha + ' 0') ;
  
  var elemGB  = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', blurX + " " + blurY) ;
  var elemGBResult = filtContext.createResultId('blur');
  DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;
  
  //attempt to use the glow strength as multiplier for alpha
  //value in blur filter
  var elemCT;
  var elemCTResult;
  if (strength != 1) {
    //BUG FIX 14394122: use feComponentTransfer instead of feColorMatrix,
    //because Chrome has issues rendering the color matrix
    elemCT = DvtSvgShapeUtils.createElement('feComponentTransfer');
    DvtSvgUtils.setAttrNullNS(elemCT, 'in', elemGBResult) ;
    elemCTResult = filtContext.createResultId('compTran');
    DvtSvgUtils.setAttrNullNS(elemCT, 'result', elemCTResult) ;
    
    var elemFA = DvtSvgShapeUtils.createElement('feFuncA');
    DvtSvgUtils.setAttrNullNS(elemFA, 'type', 'linear') ;
    DvtSvgUtils.setAttrNullNS(elemFA, 'slope', "" + strength) ;
    DvtSvgUtils.appendChildElem(elemCT, elemFA);
  }
  
  if (elemCTResult) {
    filtContext.getResultIdsUnder().push(elemCTResult);
  }
  else {
    filtContext.getResultIdsUnder().push(elemGBResult);
  }

  DvtSvgUtils.appendChildElem(filt, elemCM) ;
  DvtSvgUtils.appendChildElem(filt, elemGB) ;
  if (elemCT) {
    DvtSvgUtils.appendChildElem(filt, elemCT) ;
  }
};

/**
  * @protected
  */
/*DvtSvgGlowUtils.CreateInnerFilterPrimitives = function(filt, glow, filtContext)
{
  var red   = DvtColorUtils.getRed(glow._rgba) ;
  var green = DvtColorUtils.getGreen(glow._rgba) ;
  var blue  = DvtColorUtils.getBlue(glow._rgba) ;
  var alpha = DvtColorUtils.getAlpha(glow._rgba) ;
  var rgb = DvtColorUtils.makeRGB(red, green, blue);
  
  //filtContext.getRegionPctRect().x = 0;
  //filtContext.getRegionPctRect().y = 0;
  //filtContext.getRegionPctRect().width = 100;
  //filtContext.getRegionPctRect().height = 100;
  
  var elemGB  = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'in', 'SourceGraphic') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', glow._blurX + " " + glow._blurY) ;
  var elemGBResult = filtContext.createResultId('blur');
  DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;
  
  var elemC1  = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'operator', 'in') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in', 'SourceGraphic') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in2', elemGBResult) ;
  //if we add elemC2 below back in, then change the result
  //of this feComposite back to 'comp1'
  var elemC1Result = filtContext.createResultId('comp');
  /DvtSvgUtils.setAttrNullNS(/elemC1, 'result', elemC1Result) ;
  var elemC2Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC1, 'result', elemC2Result) ;
  
  //can add this filter back in in order to strengthen the effect
  //(that's what it appears to do...)
  //var elemC2  = DvtSvgShapeUtils.createElement('feComposite') ;
  //DvtSvgUtils.setAttrNullNS(elemC2, 'operator', 'in') ;
  //DvtSvgUtils.setAttrNullNS(elemC2, 'in2', elemC1Result) ;
  //DvtSvgUtils.setAttrNullNS(elemC2, 'result', elemC2Result) ;
  
  var elemF1  = DvtSvgShapeUtils.createElement('feFlood') ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'in', elemC2Result) ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'flood-opacity', alpha) ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'flood-color', rgb) ;
  var elemF1Result = filtContext.createResultId('flood');
  DvtSvgUtils.setAttrNullNS(elemF1, 'result', elemF1Result) ;
  
  var elemB1  = DvtSvgShapeUtils.createElement('feBlend') ;
  DvtSvgUtils.setAttrNullNS(elemB1, 'mode', 'normal') ;
  DvtSvgUtils.setAttrNullNS(elemB1, 'in', elemC2Result) ;
  DvtSvgUtils.setAttrNullNS(elemB1, 'in2', elemF1Result) ;
  var elemB1Result = filtContext.createResultId('blend');
  DvtSvgUtils.setAttrNullNS(elemB1, 'result', elemB1Result) ;
  
  var elemC3  = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC3, 'operator', 'in') ;
  DvtSvgUtils.setAttrNullNS(elemC3, 'in', elemB1Result) ;
  DvtSvgUtils.setAttrNullNS(elemC3, 'in2', 'SourceGraphic') ;
  //var elemC3Result = filtContext.createResultId('comp');
  //DvtSvgUtils.setAttrNullNS(elemC3, 'result', elemC3Result) ;
  
  DvtSvgUtils.appendChildElem(filt, elemGB) ;
  DvtSvgUtils.appendChildElem(filt, elemC1) ;
  //DvtSvgUtils.appendChildElem(filt, elemC2) ;
  DvtSvgUtils.appendChildElem(filt, elemF1) ;
  DvtSvgUtils.appendChildElem(filt, elemB1) ;
  DvtSvgUtils.appendChildElem(filt, elemC3) ;
};*/

/**
  * @protected
  */
DvtSvgGlowUtils.CreateInnerFilterPrimitives2 = function(filt, glow, filtContext)
{
  var red   = DvtColorUtils.getRed(glow._rgba) ;
  var green = DvtColorUtils.getGreen(glow._rgba) ;
  var blue  = DvtColorUtils.getBlue(glow._rgba) ;
  var alpha = DvtColorUtils.getAlpha(glow._rgba) ;
  var rgb = DvtColorUtils.makeRGB(red, green, blue);
  var strength = glow._strength;
  //adjust blur values so that SVG behaves more like Flash
  //NOTE: changed to factor of 2 for graph selection, because 
  //then the two inner glows use blurs of 1 and 2 instead of 
  //0.5 and 1 (SVG appears to treat 0.5 and 1 the same)
  var blurX = glow._blurX / 2;//4;
  var blurY = glow._blurY / 2;//4;
  
  var elemF1  = DvtSvgShapeUtils.createElement('feFlood') ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'in', 'SourceGraphic') ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'flood-opacity', alpha) ;
  DvtSvgUtils.setAttrNullNS(elemF1, 'flood-color', rgb) ;
  var elemF1Result = filtContext.createResultId('flood');
  DvtSvgUtils.setAttrNullNS(elemF1, 'result', elemF1Result) ;
  
  var elemC1  = DvtSvgShapeUtils.createElement('feComposite') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'operator', 'out') ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in', elemF1Result) ;
  DvtSvgUtils.setAttrNullNS(elemC1, 'in2', 'SourceGraphic') ;
  var elemC1Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC1, 'result', elemC1Result) ;
  
  var elemGB  = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'in', elemC1Result) ;
  DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', blurX + " " + blurY) ;
  var elemGBResult = filtContext.createResultId('blur');
  DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;
  
  //attempt to use the glow strength as multiplier for alpha
  //value in blur filter
  var elemCT;
  var elemCTResult;
  if (strength != 1) {
    //BUG FIX 14394122: use feComponentTransfer instead of feColorMatrix,
    //because Chrome has issues rendering the color matrix
    elemCT = DvtSvgShapeUtils.createElement('feComponentTransfer');
    DvtSvgUtils.setAttrNullNS(elemCT, 'in', elemGBResult) ;
    elemCTResult = filtContext.createResultId('compTran');
    DvtSvgUtils.setAttrNullNS(elemCT, 'result', elemCTResult) ;
    
    var elemFA = DvtSvgShapeUtils.createElement('feFuncA');
    DvtSvgUtils.setAttrNullNS(elemFA, 'type', 'linear') ;
    DvtSvgUtils.setAttrNullNS(elemFA, 'slope', "" + strength) ;
    DvtSvgUtils.appendChildElem(elemCT, elemFA);
  }
  
  var elemC2  = DvtSvgShapeUtils.createElement('feComposite') ;
  //DvtSvgUtils.setAttrNullNS(elemC2, 'operator', 'atop') ;
  DvtSvgUtils.setAttrNullNS(elemC2, 'operator', 'in');
  if (elemCTResult) {
    DvtSvgUtils.setAttrNullNS(elemC2, 'in', elemCTResult) ;
  }
  else {
    DvtSvgUtils.setAttrNullNS(elemC2, 'in', elemGBResult) ;
  }
  DvtSvgUtils.setAttrNullNS(elemC2, 'in2', 'SourceGraphic') ;
  var elemC2Result = filtContext.createResultId('comp');
  DvtSvgUtils.setAttrNullNS(elemC2, 'result', elemC2Result) ;
  
  filtContext.getResultIdsOver().push(elemC2Result);
  
  //if elemC2 above uses operator='in' instead of 'atop', 
  //then can do one of these afterwards to get same result:
  //var elemM  = DvtSvgShapeUtils.createElement('feMerge') ;
  //var elemMN1 = DvtSvgShapeUtils.createElement('feMergeNode') ;
  //DvtSvgUtils.setAttrNullNS(elemMN1, 'in', 'SourceGraphic') ;
  //var elemMN2 = DvtSvgShapeUtils.createElement('feMergeNode') ;
  //DvtSvgUtils.setAttrNullNS(elemMN2, 'in', elemC2Result) ;
  //OR
  //var elemC3  = DvtSvgShapeUtils.createElement('feComposite') ;
  //DvtSvgUtils.setAttrNullNS(elemC3, 'operator', 'atop') ;
  //DvtSvgUtils.setAttrNullNS(elemC3, 'in', elemC2Result) ;
  //DvtSvgUtils.setAttrNullNS(elemC3, 'in2', 'SourceGraphic') ;
  
  DvtSvgUtils.appendChildElem(filt, elemF1) ;
  DvtSvgUtils.appendChildElem(filt, elemC1) ;
  DvtSvgUtils.appendChildElem(filt, elemGB) ;
  if (elemCT) {
    DvtSvgUtils.appendChildElem(filt, elemCT);
  }
  DvtSvgUtils.appendChildElem(filt, elemC2) ;
  
  //DvtSvgUtils.appendChildElem(filt, elemM) ;
  //DvtSvgUtils.appendChildElem(elemM, elemMN1) ;
  //DvtSvgUtils.appendChildElem(elemM, elemMN2) ;
  //OR
  //DvtSvgUtils.appendChildElem(filt, elemC3) ;
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------------*/
/*    DvtSvgGradientUtils    A static class for SVG gradient property manip- */
/*                           ulation.                                        */
/*---------------------------------------------------------------------------*/
/**
  *   DvtSvgGradientUtils    A static class for SVG gradient property manipulation.
  *   @class DvtSvgGradientUtils 
  *   @constructor
  */
var  DvtSvgGradientUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgGradientUtils, DvtObj, "DvtSvgGradientUtils");

/**
  *  Static method to create an SVG element and apply gradient properties to it.
  *  @param {Object}  Either a DvtGradientFill or DvtGradientStroke derivative to apply.
  */
DvtSvgGradientUtils.createElem = function(grad, id)
{
   var bLinear = ((grad instanceof DvtLinearGradientFill) || (grad instanceof DvtLinearGradientStroke));
   var elemGrad = DvtSvgShapeUtils.createElement((bLinear? 'linearGradient' : 'radialGradient'), id) ;

   var i ;
   var arColors = grad.getColors() ;
   var arAlphas = grad.getAlphas() ;
   var arStops  = grad.getStops() ;
   var arBounds = grad.getBounds() ;
   var len      = arColors.length ;

   for (i = 0; i < len; i++) {
      var elem = DvtSvgShapeUtils.createElement('stop') ;
      DvtSvgUtils.setAttrNullNS(elem, 'offset', '' + (arStops[i] * 100) + '%') ;
      var color = arColors[i];
      if (color) {
        var alpha = arAlphas[i];
        // Workaround for Safari where versions < 5.1 show rgba values as black
        if (DvtAgent.isBrowserSafari() && color.indexOf("rgba") !==  - 1) {
          DvtSvgUtils.setAttrNullNS(elem, 'stop-color', DvtColorUtils.getRGB(color));
          // Use alpa in rgba value as a multiplier to the alpha set on the object as this is what svg does.
          if (alpha != null)
            DvtSvgUtils.setAttrNullNS(elem, 'stop-opacity', DvtColorUtils.getAlpha(color) * alpha);
          else 
            DvtSvgUtils.setAttrNullNS(elem, 'stop-opacity', DvtColorUtils.getAlpha(color));
        }
        else {
          DvtSvgUtils.setAttrNullNS(elem, 'stop-color', color);
          if (alpha != null)
            DvtSvgUtils.setAttrNullNS(elem, 'stop-opacity', alpha);
        }
      }
      DvtSvgUtils.appendChildElem(elemGrad, elem) ;
   }

   //  If no gradient bounding box specified, will use the object's boundary box.

   var bUseObjBBox = (! arBounds ||
                    ((arBounds[0]==0) && (arBounds[1]==0) && (arBounds[2]==0) && (arBounds[3]==0)) );

   //  The angle of rotation for SVG is clockwise, so must convert from the standard
   //  anti-clockwise convention used by the middle-tier xml. Rotation is
   //  at the mid-point of the bounding box.

   if (bLinear) {
     var  angle = grad.getAngle() ;

     var  x1 = '0%' ;
     var  y1 = '0%' ;
     var  x2 = '100%' ;
     var  y2 = '0%' ;

     var setGradientVector = true;
      
     if (bUseObjBBox) {

       // Set gradient vector for gradientUnits = "objectBoundingBox"
       // (the default value for gradientUnits).

       if (angle === 45) {
         y1 = '100%' ;
         x2 = '100%' ;
       }
       else if (angle === 90) {
         y1 = '100%' ;
         x2 = '0%' ;
       }
       else if (angle === 135) {
         x1 = '100%' ;
         x2 = '0%' ;
         y2 = '100%' ;
       }
       else if (angle === 270) {
         x2 = '0%' ;
         y2 = '100%' ;
       }
       else if (angle !== 0) {
         angle = -angle ;
         DvtSvgUtils.setAttrNullNS(elemGrad, 'gradientTransform', 'rotate(' + angle + ' ' + '.5 .5)' ) ;
         setGradientVector = false;  // no need to change the default gradient vector, since we are rotating the 
                                     // gradient via gradientTransform
       }
     } 
     else  {

      //  Apply specified bounding box

      // use gradientUnits = "userSpaceOnUse"; for when we want to account for bounding box
      // first rotate the gradient by the specified angle
      // then scale this gradient to the width and bounds specifed in arBounds
      // then translate the gradient
      // note that if the width and height of the gradient are not equal, then the actual angle of the
      // gradient is different from the specified angle argument
      // However, this is the same behavior as how Flash processes the bounding box argument
      // Finally, note that in SVG, the order of transform operations is right to left

      DvtSvgUtils.setAttrNullNS(elemGrad, 'gradientUnits', 'userSpaceOnUse') ;

      // set gradient vector to span the middle of the unit square
      x1 = '0';
      y1 = '0.5';
      x2 = '1';
      y2 = '0.5';

      var scaleX     = arBounds[2];
      var scaleY     = arBounds[3];
      var translateX = arBounds[0];
      var translateY = arBounds[1];
        
      angle = -angle;
      var rotateTransformStr = 'rotate(' + angle + ' ' + '.5 .5)'
      var scaleTransformStr = 'scale('+ scaleX + ' ' + scaleY + ')';
      var translateTransformStr = 'translate(' + translateX + ' ' + translateY + ')';
      var boundingBoxTransformStr = scaleTransformStr + ' ' + rotateTransformStr;
      
      if (translateX != 0 || translateY != 0) {
        boundingBoxTransformStr = translateTransformStr + ' ' + boundingBoxTransformStr;
      } 
        
      // in the case of a bounding box, to set up the gradient, we need both gradientTransform and
      // a gradient vector centered in the unit square

      DvtSvgUtils.setAttrNullNS(elemGrad, 'gradientTransform', boundingBoxTransformStr ) ;
     }

     if(setGradientVector)   {
       DvtSvgUtils.setAttrNullNS(elemGrad, 'x1', x1) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'y1', y1) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'x2', x2) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'y2', y2) ;
     }
   }
   else {    //  Radial gradient

     if (! bUseObjBBox) {

       DvtSvgUtils.setAttrNullNS(elemGrad, 'gradientUnits', 'userSpaceOnUse') ;

       DvtSvgUtils.setAttrNullNS(elemGrad, 'cx', grad.getCx()) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'cy', grad.getCy()) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'fx', grad.getCx()) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'fy', grad.getCy()) ;
       DvtSvgUtils.setAttrNullNS(elemGrad, 'r',  grad.getRadius()) ;
    }
   }
   return elemGrad ;
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------------*/
/*    DvtSvgImageFillUtils    A static class for SVG image fill property     */
/*                           manipulation.                                   */
/*---------------------------------------------------------------------------*/
/**
  *   A static class for SVG image fill property manipulation.
  *   @class DvtSvgImageFillUtils
  *   @constructor
  */
var  DvtSvgImageFillUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgImageFillUtils, DvtObj, "DvtSvgImageFillUtils");

/**
  *  Static method to create an SVG element and apply image fill properties 
  *  to it.
  *  @param {DvtImageFill}
  */
DvtSvgImageFillUtils.createElem = function(imageFill, id)
{
   /* Example:
      <defs>
        <pattern id="img1" patternUnits="userSpaceOnUse" width="20" height="20" >
          <image xlink:href="400.png" x="0" y="0"  width="20" height="20" />
        </pattern>
      </defs>

      <rect x="0" y="0" height="100" width="100" fill="url(#img1)"/>
   */

   var elemPat = DvtSvgShapeUtils.createElement("pattern", id) ;
   var elemImg  = DvtSvgShapeUtils.createElement("image", id);

   var src = imageFill.getSrc() ;
   var bound = imageFill.getBound() ;
   var repeat = imageFill.getRepeat();

   if (bound) {
      DvtSvgUtils.setAttrNullNS(elemPat, 'x', bound.x);
      DvtSvgUtils.setAttrNullNS(elemPat, 'y', bound.y);

      DvtSvgUtils.setAttrNullNS(elemImg, "x", bound.x);
      DvtSvgUtils.setAttrNullNS(elemImg, "y", bound.y);

      DvtSvgUtils.setAttrNullNS(elemPat, 'width', bound.w);
      DvtSvgUtils.setAttrNullNS(elemPat, 'height', bound.h);

      DvtSvgUtils.setAttrNullNS(elemImg, "width", bound.w);
      DvtSvgUtils.setAttrNullNS(elemImg, "height", bound.h);
      DvtSvgUtils.setAttrNullNS(elemPat, "patternUnits", "userSpaceOnUse");

      /*
      // tile the background image
      if (! repeat || repeat != "no-repeat") {
      }
      // stretch out the background image
      else {
        DvtSvgUtils.setAttrNullNS(elemPat, "patternUnits", "objectBoundingBox");
        DvtSvgUtils.setAttrNullNS(elemPat, 'width', "100%");
        DvtSvgUtils.setAttrNullNS(elemPat, 'height', "100%");
      }
      */

      if (src) {
         DvtSvgUtils.setAttrNS(elemImg, DvtSvgImage.XLINK_NS, 'xlink:href', src) ;
      }
   }

   DvtSvgUtils.appendChildElem(elemPat, elemImg) ;

   return elemPat ;
};
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------------*/
/*    DvtSvgPatternFillUtils    A static class for SVG pattern fill property */
/*                              manipulation.                                */
/*---------------------------------------------------------------------------*/
/**
  *   A static class for creating SVG pattern fills.
  *   @class DvtSvgPatternFillUtils
  *   @constructor
  */
var  DvtSvgPatternFillUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgPatternFillUtils, DvtObj, "DvtSvgPatternFillUtils");

/**   @private @final @type String  */
DvtSvgPatternFillUtils._SM_WIDTH       = 8 ;
/**   @private @final @type String  */
DvtSvgPatternFillUtils._SM_HEIGHT      = 8 ;
/**   @private @final @type String  */
DvtSvgPatternFillUtils._LG_WIDTH       = 16 ;
/**   @private @final @type String  */
DvtSvgPatternFillUtils._LG_HEIGHT      = 16 ;

/**
  *  Static method to create an SVG pattern element.
  *  @param {DvtPatternFill}  patternFill  pattern fill object
  *  @param {string}  id  pattern identifier
  */
DvtSvgPatternFillUtils.createElem = function(patternFill, id)
{
  var elemPat = DvtSvgShapeUtils.createElement("pattern", id) ;

  var pattern = patternFill.getPattern();
  var bSmall = DvtSvgPatternFillUtils.IsSmallPattern(pattern);
  var ww;
  var hh;
  if (bSmall)
  {
    ww = DvtSvgPatternFillUtils._SM_WIDTH ;
    hh = DvtSvgPatternFillUtils._SM_HEIGHT ;
  }
  else
  {
    ww = DvtSvgPatternFillUtils._LG_WIDTH ;
    hh = DvtSvgPatternFillUtils._LG_HEIGHT ;
  }

  DvtSvgUtils.setAttrNullNS(elemPat, "x", 0);
  DvtSvgUtils.setAttrNullNS(elemPat, "y", 0);
  DvtSvgUtils.setAttrNullNS(elemPat, "width", ww);
  DvtSvgUtils.setAttrNullNS(elemPat, "height", hh);
  DvtSvgUtils.setAttrNullNS(elemPat, "patternUnits", "userSpaceOnUse");
  var mat = patternFill.getMatrix();
  if (mat) {
    var sMat = 'matrix(' + mat.getA() + ',' + mat.getC() + ',' + mat.getB() + ',' + mat.getD() + ',' + mat.getTx() + ',' + mat.getTy() + ')';
    DvtSvgUtils.setAttrNullNS(elemPat, "patternTransform", sMat);
  }
  
  DvtSvgPatternFillUtils.CreatePatternElems(patternFill, elemPat);

  return elemPat ;
};

/**
  * Determine if the pattern is large or small.
  * 
  * @param {string}  pattern  constant representing the pattern
  * @protected
  */
DvtSvgPatternFillUtils.IsSmallPattern = function(pattern)
{
  return (pattern.charAt(0) === 's');
};

/**
  * Determine if the pattern is large or small.
  * 
  * @param {DvtPatternFill}  patternFill  pattern fill object
  * @param {object}  parentElem  parent pattern DOM element
  * @protected
  */
DvtSvgPatternFillUtils.CreatePatternElems = function(patternFill, parentElem)
{
  var rightX ;
  var bottomY ;
  var w ;
  var h ;
  var halfW ;  
  var halfH ; 
  var elem ;

  var pattern = patternFill.getPattern();
  var sColor = patternFill.getColor();
  var color = DvtColorUtils.getRGB(sColor);
  var alpha = DvtColorUtils.getAlpha(sColor);
  var sBackgroundColor = patternFill.getBackgroundColor();
  var backgroundColor = DvtColorUtils.getRGB(sBackgroundColor);
  var backgroundAlpha = DvtColorUtils.getAlpha(sBackgroundColor);
  
  var bSmall = DvtSvgPatternFillUtils.IsSmallPattern(pattern);
  if (bSmall)
  {
    rightX  = DvtSvgPatternFillUtils._SM_WIDTH  ;
    bottomY = DvtSvgPatternFillUtils._SM_HEIGHT  ;
    w       = DvtSvgPatternFillUtils._SM_WIDTH ;
    h       = DvtSvgPatternFillUtils._SM_HEIGHT ;
  }
  else
  {
    rightX  = DvtSvgPatternFillUtils._LG_WIDTH  ;
    bottomY = DvtSvgPatternFillUtils._LG_HEIGHT  ;
    w       = DvtSvgPatternFillUtils._LG_WIDTH ;
    h       = DvtSvgPatternFillUtils._LG_HEIGHT ;
  }
  
  //if a background color is specified, then fill a rect with that color
  //before drawing the pattern elements on top of it
  if (backgroundColor && (backgroundAlpha > 0))
  {
    elem = DvtSvgShapeUtils.createElement("rect");
    
    DvtSvgUtils.setAttrNullNS(elem, "stroke", backgroundColor);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", backgroundAlpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    DvtSvgUtils.setAttrNullNS(elem, "fill", backgroundColor);
    DvtSvgUtils.setAttrNullNS(elem, "fill-opacity", backgroundAlpha);
    
    DvtSvgUtils.setAttrNullNS(elem, "x", 0);
    DvtSvgUtils.setAttrNullNS(elem, "y", 0);
    DvtSvgUtils.setAttrNullNS(elem, "width", rightX);
    DvtSvgUtils.setAttrNullNS(elem, "height", bottomY);
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }

  if (pattern === DvtPatternFill.SM_DIAG_UP_LT || 
      pattern === DvtPatternFill.LG_DIAG_UP_LT)
  {
    elem = DvtSvgShapeUtils.createElement("path");
    DvtSvgUtils.setAttrNullNS(elem, "stroke", color);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", alpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-linecap", "square");
    
    DvtSvgUtils.setAttrNullNS(elem, "d", DvtPathUtils.moveTo(0, -h/2) + DvtPathUtils.lineTo(3*w/2, h) + 
                                   DvtPathUtils.moveTo(-w/2, 0) + DvtPathUtils.lineTo(w/2, h)); 
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }
  else if (pattern === DvtPatternFill.SM_DIAG_UP_RT || 
           pattern === DvtPatternFill.LG_DIAG_UP_RT)
  {
    elem = DvtSvgShapeUtils.createElement("path");
    DvtSvgUtils.setAttrNullNS(elem, "stroke", color);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", alpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-linecap", "square");
    
    DvtSvgUtils.setAttrNullNS(elem, "d", DvtPathUtils.moveTo(-w/2, h) + DvtPathUtils.lineTo(w, -h/2) + 
                                   DvtPathUtils.moveTo(0, 3*h/2) + DvtPathUtils.lineTo(3*w/2, 0)); 
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }
  else if (pattern === DvtPatternFill.SM_CROSSHATCH || 
           pattern === DvtPatternFill.LG_CROSSHATCH)
  {
    //use path instead of two lines because it's more compact (uses one
    //DOM element instead of two)
    elem = DvtSvgShapeUtils.createElement("path");

//  g.lineStyle((bSmall? 1 : 2), color) ;
    DvtSvgUtils.setAttrNullNS(elem, "stroke", color);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", alpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    
    DvtSvgUtils.setAttrNullNS(elem, "d", "M0,0" + 
                                   "L" + rightX + "," + bottomY + 
                                   "M" + rightX + ",0" + 
                                   "L0," + bottomY);
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }
  else if (pattern === DvtPatternFill.SM_CHECK || 
           pattern === DvtPatternFill.LG_CHECK)
  {
    halfW = w/2 ;  
    halfH = h/2 ;  
    
    //use path instead of two rects because it's more compact (uses one
    //DOM element instead of two)
    elem = DvtSvgShapeUtils.createElement("path");
    
    DvtSvgUtils.setAttrNullNS(elem, "stroke", color);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", alpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    DvtSvgUtils.setAttrNullNS(elem, "fill", color);
    DvtSvgUtils.setAttrNullNS(elem, "fill-opacity", alpha);
    
    DvtSvgUtils.setAttrNullNS(elem, "d", "M" + halfW + ",0" + 
                                   "L" + w + ",0" + 
                                   "L" + w + "," + halfH + 
                                   "L" + halfW + "," + halfH + "Z" + 
                                   "M0," + halfH + 
                                   "L" + halfW + "," + halfH + 
                                   "L" + halfW + "," + h + 
                                   "L0," + h + "Z");
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }
  else if (pattern === DvtPatternFill.SM_TRIANGLE_CHECK || 
           pattern === DvtPatternFill.LG_TRIANGLE_CHECK)
  {
    elem = DvtSvgShapeUtils.createElement("polygon");
    
    DvtSvgUtils.setAttrNullNS(elem, "stroke", color);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", alpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    DvtSvgUtils.setAttrNullNS(elem, "fill", color);
    DvtSvgUtils.setAttrNullNS(elem, "fill-opacity", alpha);
    
    DvtSvgUtils.setAttrNullNS(elem, "points", "0," + bottomY + " " + 
                                        rightX + ",0 " + 
                                        rightX + "," + bottomY);
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }
  else if (pattern === DvtPatternFill.SM_DIAMOND_CHECK || 
           pattern === DvtPatternFill.LG_DIAMOND_CHECK)
  {
    halfW = w/2 ;  
    halfH = h/2 ;  
    
    elem = DvtSvgShapeUtils.createElement("polygon");
    
    DvtSvgUtils.setAttrNullNS(elem, "stroke", color);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-opacity", alpha);
    DvtSvgUtils.setAttrNullNS(elem, "stroke-width", 1);
    DvtSvgUtils.setAttrNullNS(elem, "fill", color);
    DvtSvgUtils.setAttrNullNS(elem, "fill-opacity", alpha);
    
    DvtSvgUtils.setAttrNullNS(elem, "points", "0," + halfH + " " + 
                                        halfW + ",0 " + 
                                        rightX + "," + halfW + " " + 
                                        halfW + "," + bottomY);
    
    DvtSvgUtils.appendChildElem(parentElem, elem);
  }
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------------*/
/*   DvtSvgShadowUtils    A static class for SVG drop shadow property manip- */
/*                        ulation.                                           */
/*---------------------------------------------------------------------------*/
/**
  *  A static class for SVG drop shadow property manipulation.
  *  @class DvtSvgShadowUtils
  *  @constructor
  */
var  DvtSvgShadowUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgShadowUtils, DvtObj, "DvtSvgShadowUtils");

/**
 * @private
 * @final
 */
DvtSvgShadowUtils.RADS_PER_DEGREE = (Math.PI / 180);


/**
  *  Static method to create an SVG filter element and apply shadow properties to it.
  *  @param {DvtShadow}
  *  @returns {DOM_Element}  An SVG  &lt;filter&gt; element
  */
DvtSvgShadowUtils.createFilter = function(shadow, displayable)
{
   //  The following filter is created:

   //   <filter id="ds1">
   //     <feColorMatrix type="matrix" values="0 0 0 red 0
   //                                          0 0 0 green 0
   //                                          0 0 0 blue 0
   //                                          0 0 0 alpha 0">
   //     </feColorMatrix>
   //     <feGaussianBlur stdDeviation="5.166666666666666" result="blur1"></feGaussianBlur>
   //     <feOffset dx="5.75" dy="5.75" in="blur1" result="offset"></feOffset>
   //     <feMerge>
   //       <feMergeNode in="offset"></feMergeNode>
   //       <feMergeNode in="SourceGraphic"></feMergeNode>
   //     </feMerge>
   //   </filter>

   var filt ;

   if (! shadow.isLocked()) {
     var filtContext = new DvtSvgFilterContext();
     filt = DvtSvgShapeUtils.createElement('filter', shadow._Id) ;
     DvtSvgShadowUtils.createFilterPrimitives(filt, shadow, displayable, filtContext);
     
     var elemM  = DvtSvgShapeUtils.createElement('feMerge') ;
     var elemMN1 = DvtSvgShapeUtils.createElement('feMergeNode') ;
     DvtSvgUtils.setAttrNullNS(elemMN1, 'in', filtContext.getResultIdsUnder()[0]) ;
     var elemMN2 = DvtSvgShapeUtils.createElement('feMergeNode') ;
     DvtSvgUtils.setAttrNullNS(elemMN2, 'in', 'SourceGraphic') ;
     
     DvtSvgUtils.appendChildElem(filt, elemM) ;
     DvtSvgUtils.appendChildElem(elemM, elemMN1) ;
     DvtSvgUtils.appendChildElem(elemM, elemMN2) ;
   }
   
   return filt;
};

DvtSvgShadowUtils.createFilterPrimitives = function(filt, shadow, svgDisplayable, filtContext)
{
   //BUG FIX #12407873: create inner shadow if necessary
   if (shadow._bInner)
   {
     DvtSvgShadowUtils.CreateInnerFilterPrimitives(filt, shadow, svgDisplayable, filtContext);
   }
   else
   {
     DvtSvgShadowUtils.CreateOuterFilterPrimitives(filt, shadow, svgDisplayable, filtContext);
   }
};

/**
 * @protected
 */
DvtSvgShadowUtils.CreateOuterFilterPrimitives = function(filt, shadow, svgDisplayable, filtContext)
{
   //if (! shadow.isLocked()) {

     var rgba  = shadow._rgba ;
     var red   = DvtColorUtils.getRed(rgba)/255 ;
     var green = DvtColorUtils.getGreen(rgba)/255 ;
     var blue  = DvtColorUtils.getBlue(rgba)/255 ;
     var alpha = DvtColorUtils.getAlpha(rgba) ;
     var strength = shadow._strength;
     
     var origBlurX = shadow._blurX;
     var origBlurY = shadow._blurY;
     //adjust blur values so that SVG behaves more like Flash
     //BUG FIX #12661565: only calculate blur if blur is not set to 0
     var blurX = 0;
     var blurY = 0;
     if (shadow._blurX > 0)
     {
       blurX = Math.max(shadow._blurX / 3, 1);
     }
     if (shadow._blurY > 0)
     {
       blurY = Math.max(shadow._blurY / 3, 1);
     }
     var distance = shadow._distance;
     var angleDegs = shadow._angle;
     
     var angleRads = angleDegs * DvtSvgShadowUtils.RADS_PER_DEGREE;
     var dx = Math.cos(angleRads) * distance;
     var dy = Math.sin(angleRads) * distance;

     //BUG FIX #12427741: 
     //if we have a boundsRect, increase the size of the filter so
     //that the shadow has room to display outside the shape
     var boundsRect = svgDisplayable.getDimensions(svgDisplayable.getParent());
     if (boundsRect)
     {
       //try to optimize based on how much of the shadow falls
       //on each side of the bounding box
       var absDistance = Math.abs(distance);
       //use two times the blur by default, because using it directly
       //still clips the shadow
       var padLeft = 2 * origBlurX;
       var padRight = 2 * origBlurX;
       var padTop = 2 * origBlurY;
       var padBottom = 2 * origBlurY;
       if (distance > 0)
       {
         padLeft -= absDistance;
         padTop -= absDistance;
         padRight += absDistance;
         padBottom += absDistance;
       }
       else if (distance < 0)
       {
         padLeft += absDistance;
         padTop += absDistance;
         padRight -= absDistance;
         padBottom -= absDistance;
       }
       if (padLeft < 0)
       {
         padLeft = 0;
       }
       if (padTop < 0)
       {
         padTop = 0;
       }
       if (padRight < 0)
       {
         padRight = 0;
       }
       if (padBottom < 0)
       {
         padBottom = 0;
       }
       var ratioLeft = (padLeft / boundsRect.w) * 100;
       var ratioRight = (padRight / boundsRect.w) * 100;
       var ratioTop = (padTop / boundsRect.h) * 100;
       var ratioBottom = (padBottom / boundsRect.h) * 100;
       if (filtContext.getRegionPctRect().x > -ratioLeft)
       {
         filtContext.getRegionPctRect().x = -ratioLeft;
       }
       if (filtContext.getRegionPctRect().y > -ratioTop)
       {
         filtContext.getRegionPctRect().y = -ratioTop;
       }
       if (filtContext.getRegionPctRect().w < (100 + ratioLeft + ratioRight))
       {
         filtContext.getRegionPctRect().w = (100 + ratioLeft + ratioRight);
       }
       if (filtContext.getRegionPctRect().h < (100 + ratioTop + ratioBottom))
       {
         filtContext.getRegionPctRect().h = (100 + ratioTop + ratioBottom);
       }
     }
     // The bounding box does not take into accoutn stroke-width. Need to adjust for DvtLine objects
     if (svgDisplayable instanceof DvtSvgPolyline) {
         var strokeWidth = svgDisplayable.getStroke().getWidth();
         // If stroke is wider than 1 pixel, adjust y coordinate and height of shadow bounding box
         if (strokeWidth > 1) {
             filtContext.getRegionPctRect().h = filtContext.getRegionPctRect().h + strokeWidth;
             filtContext.getRegionPctRect().y = filtContext.getRegionPctRect().y - strokeWidth;
         }
     }

     var elemCM  = DvtSvgShapeUtils.createElement('feColorMatrix') ;
     DvtSvgUtils.setAttrNullNS(elemCM, 'in', 'SourceGraphic') ;
     DvtSvgUtils.setAttrNullNS(elemCM, 'type', 'matrix') ;
     DvtSvgUtils.setAttrNullNS(elemCM, 'values', '0 0 0 ' + red   + ' 0 ' +
                                          '0 0 0 ' + green + ' 0 ' +
                                          '0 0 0 ' + blue  + ' 0 ' +
                                          '0 0 0 ' + alpha*strength + ' 0') ;
     //var elemCMResult = filtContext.createResultId('colorMatrix');
     //DvtSvgUtils.setAttrNullNS(elemCM, 'result', elemCMResult) ;

     var elemGB  = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
     //include both numbers for stdDev when necessary
     var stdDev = blurX;
     if (blurX !== blurY)
     {
       stdDev += " " + blurY;
     }
     DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', stdDev) ;
     var elemGBResult = filtContext.createResultId('blur');
     DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;

     var elemO  = DvtSvgShapeUtils.createElement('feOffset') ;
     DvtSvgUtils.setAttrNullNS(elemO, 'dx', dx) ;
     DvtSvgUtils.setAttrNullNS(elemO, 'dy', dy) ;
     DvtSvgUtils.setAttrNullNS(elemO, 'in', elemGBResult) ;
     var elemOResult = filtContext.createResultId('offset');
     DvtSvgUtils.setAttrNullNS(elemO, 'result', elemOResult) ;
     
     filtContext.getResultIdsUnder().push(elemOResult);

     DvtSvgUtils.appendChildElem(filt, elemCM) ;
     DvtSvgUtils.appendChildElem(filt, elemGB) ;
     DvtSvgUtils.appendChildElem(filt, elemO) ;


// TDO <feMorphology operator="erode" in="blurred" radius="3" result="eroded"/>
   //}
};

/**
 * @protected
 */
DvtSvgShadowUtils.CreateInnerFilterPrimitives = function(filt, shadow, svgDisplayable, filtContext)
{
   var rgba  = shadow._rgba ;
   var red   = DvtColorUtils.getRed(rgba)/255 ;
   var green = DvtColorUtils.getGreen(rgba)/255 ;
   var blue  = DvtColorUtils.getBlue(rgba)/255 ;
   var rgb   = DvtColorUtils.makeRGB(red, green, blue);
   var alpha = DvtColorUtils.getAlpha(rgba) ;
   
   var origBlurX = shadow._blurX;
   var origBlurY = shadow._blurY;
   //adjust blur values so that SVG behaves more like Flash
   var blurX = Math.max(shadow._blurX / 2, 1);
   var blurY = Math.max(shadow._blurY / 2, 1);
   var distance = shadow._distance;
   var angleDegs = shadow._angle;
   var strength = shadow._strength;
   
   var angleRads = angleDegs * DvtSvgShadowUtils.RADS_PER_DEGREE;
   var dx = Math.cos(angleRads) * distance;
   var dy = Math.sin(angleRads) * distance;
  
   var elemF1  = DvtSvgShapeUtils.createElement('feFlood') ;
   DvtSvgUtils.setAttrNullNS(elemF1, 'in', 'SourceGraphic') ;
   DvtSvgUtils.setAttrNullNS(elemF1, 'flood-opacity', alpha) ;
   DvtSvgUtils.setAttrNullNS(elemF1, 'flood-color', rgb) ;
   var elemF1Result = filtContext.createResultId('flood');
   DvtSvgUtils.setAttrNullNS(elemF1, 'result', elemF1Result) ;
   
   var elemC1  = DvtSvgShapeUtils.createElement('feComposite') ;
   DvtSvgUtils.setAttrNullNS(elemC1, 'operator', 'out') ;
   DvtSvgUtils.setAttrNullNS(elemC1, 'in', elemF1Result) ;
   DvtSvgUtils.setAttrNullNS(elemC1, 'in2', 'SourceGraphic') ;
   //var elemC1Result = filtContext.createResultId('comp');
   //DvtSvgUtils.setAttrNullNS(elemC1, 'result', elemC1Result) ;

/*
   var elemCM  = DvtSvgShapeUtils.createElement('feColorMatrix') ;
   DvtSvgUtils.setAttrNullNS(elemCM, 'in', 'SourceGraphic') ;
   DvtSvgUtils.setAttrNullNS(elemCM, 'type', 'matrix') ;
   DvtSvgUtils.setAttrNullNS(elemCM, 'values', '0 0 0 ' + red   + ' 0 ' +
                                        '0 0 0 ' + green + ' 0 ' +
                                        '0 0 0 ' + blue  + ' 0 ' +
                                        '0 0 0 ' + alpha + ' 0') ;
   //var elemCMResult = filtContext.createResultId('colorMatrix');
   //DvtSvgUtils.setAttrNullNS(elemCM, 'result', elemCMResult) ;
*/

   var elemGB  = DvtSvgShapeUtils.createElement('feGaussianBlur') ;
   //include both numbers for stdDev when necessary
   var stdDev = blurX;
   if (blurX !== blurY)
   {
     stdDev += " " + blurY;
   }
   DvtSvgUtils.setAttrNullNS(elemGB, 'stdDeviation', stdDev) ;
   var elemGBResult = filtContext.createResultId('blur');
   DvtSvgUtils.setAttrNullNS(elemGB, 'result', elemGBResult) ;
   
   //attempt to use the shadow strength as multiplier for alpha
   //value in blur filter
   var elemCM2  = DvtSvgShapeUtils.createElement('feColorMatrix') ;
   DvtSvgUtils.setAttrNullNS(elemCM2, 'in', elemGBResult) ;
   DvtSvgUtils.setAttrNullNS(elemCM2, 'type', 'matrix') ;
   DvtSvgUtils.setAttrNullNS(elemCM2, 'values', '1 0 0 0 0 ' +
                                        '0 1 0 0 0 ' +
                                        '0 0 1 0 0 ' +
                                        '0 0 0 ' + strength + ' 0') ;
   var elemCM2Result = filtContext.createResultId('colMat');
   DvtSvgUtils.setAttrNullNS(elemCM2, 'result', elemCM2Result) ;

   var elemO  = DvtSvgShapeUtils.createElement('feOffset') ;
   DvtSvgUtils.setAttrNullNS(elemO, 'dx', dx) ;
   DvtSvgUtils.setAttrNullNS(elemO, 'dy', dy) ;
   DvtSvgUtils.setAttrNullNS(elemO, 'in', elemCM2Result) ;
   var elemOResult = filtContext.createResultId('offset');
   DvtSvgUtils.setAttrNullNS(elemO, 'result', elemOResult) ;
   
   var elemC2  = DvtSvgShapeUtils.createElement('feComposite') ;
   DvtSvgUtils.setAttrNullNS(elemC2, 'operator', 'in') ;
   DvtSvgUtils.setAttrNullNS(elemC2, 'in', elemOResult) ;
   DvtSvgUtils.setAttrNullNS(elemC2, 'in2', 'SourceGraphic') ;
   var elemC2Result = filtContext.createResultId('comp');
   DvtSvgUtils.setAttrNullNS(elemC2, 'result', elemC2Result) ;
   
   filtContext.getResultIdsOver().push(elemC2Result);

   DvtSvgUtils.appendChildElem(filt, elemF1) ;
   DvtSvgUtils.appendChildElem(filt, elemC1) ;
   //DvtSvgUtils.appendChildElem(filt, elemCM) ;
   DvtSvgUtils.appendChildElem(filt, elemGB) ;
   DvtSvgUtils.appendChildElem(filt, elemCM2) ;
   DvtSvgUtils.appendChildElem(filt, elemO) ;
   DvtSvgUtils.appendChildElem(filt, elemC2) ;
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*  DvtSvgDisplayable      Svg implementation of DvtDisplayable        */
/*---------------------------------------------------------------------*/
/**
  *  SVG implementation of base displayable object DvtDisplayable.
  *  @extends DvtObj
  *  @class DvtSvgDisplayable is the SVG implementation base class for all displayable
  *  objects (derived from {@link DvtSvgDisplayable}).
  *  Must be superclassed  - do not use directly - all derivatives of DvtSvgDisplayable
  *  should be created via a specific platform factory implementation.
  *  @constructor  
  *  @param {String} id    The object ID (if undefined or null, '?' is used.
  *  @param {String} type  The SVG DOM element type.
  */
var   DvtSvgDisplayable = function(id, type)
{
  this._Init(id) ; 
};


DvtObj.createSubclass(DvtSvgDisplayable, DvtObj, "DvtSvgDisplayable") ;

/**
 * Array of SVG attributes that should be transferred to the outer element.
 * @private
 */
DvtSvgDisplayable._ATTRS_TRANSFERABLE_TO_OUTER = [/*'filter',*/ 'clip-path']

/**
 * A mapping between event types and the string needed to create a new event for dispatch
 * @private
 */
DvtSvgDisplayable._CREATE_EVENT_TYPE_MAP = {click:DvtMouseEvent.CLICK,
                                            mouseover:DvtMouseEvent.MOUSEOVER,
                                            mouseout:DvtMouseEvent.MOUSEOUT,
                                            mousemove:DvtMouseEvent.MOUSEMOVE,
                                            keydown:DvtKeyboardEvent.KEYDOWN,
                                            keyup:DvtKeyboardEvent.KEYUP
                                           };

/*---------------------------------------------------------------------*/
/*   _Init()                                                           */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtSvgDisplayable.prototype._Init = function(id, type)
{
  if (id) {
    this._id = id ;
  }
  this._Parent  = null ;
  this._elem  = DvtSvgShapeUtils.createElement(type, this._id) ;
  this._elem._obj = this;    //  pointer back to this object
  
  this._bVisible      = true;
  this._filter        = null;
  this._pixelHinting  = false ;
  this._cursor        = null;
  this._bMouseEnabled = true;
  this._alpha         = 1;
  this._matrix        = null;
  
  this._bubbleClosure = null;
  this._captureClosure = null;
  this._desc = null;
} ;




/*---------------------------------------------------------------------*/
/*    getElem()         Return the SVG element for this object         */
/*---------------------------------------------------------------------*/
/**
  *  Returns the SVG DOM element representing this displayable object.
  *  @returns {DOM_element}  An SVG DOM element representing this displayable object.
  */
DvtSvgDisplayable.prototype.getElem = function()
{
   return  this._elem ;
} ;

/**
 * Returns the outermost SVG DOM element of this displayable.  This should be used when
 * removing this displayable from the DOM.
 * @return {DvtSvgDisplayable}
 */
DvtSvgDisplayable.prototype.getOuterElem = function() {
  return this._outerElem ? this._outerElem : this.getElem();
}

/*---------------------------------------------------------------------*/
/*   get/setId()                                                       */
/*---------------------------------------------------------------------*/
/**
  *   @returns {String}  the id of this shape.
  */
DvtSvgDisplayable.prototype.getId = function()
{
  return this._id;
};

/**
  *   Sets the id of this shape.
  *   @param {String} id  The id for the shape.
  */
DvtSvgDisplayable.prototype.setId = function(id)
{
  if (this._id !== id) {
    if (id && id.length === 0) {
      id = null;
    }
    this._id = id;
     
    if (id)
      DvtSvgUtils.setAttrNullNS(this._elem, 'id', id);
    else
      DvtSvgUtils.removeAttrNullNS(this._elem, 'id');
  }
};


/*---------------------------------------------------------------------*/
/*   getObj()/setObj     Get/Set the controlling (js) object for this  */
/*                       implementation object.                        */
/*---------------------------------------------------------------------*/
/**
  *  @returns {Object}  the controlling (js) object.
  */
DvtSvgDisplayable.prototype.getObj = function()
{
   return this._obj ;
} ;

DvtSvgDisplayable.prototype.setObj = function(obj)
{
   this._obj = obj ;
} ;

/*---------------------------------------------------------------------*/
/*   get/setParent()                                                   */
/*---------------------------------------------------------------------*/
/**
  *  @returns {Object} the (js) parent of this shape.
  */
DvtSvgDisplayable.prototype.getParent = function()
{
   return this._obj.getParent() ;
} ;

/**
  *  Sets the (js) parent of this shape.
  *  @param {Object} parent
  */
DvtSvgDisplayable.prototype.setParent = function(parent)
{
   this._obj.setParent(parent) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setPixelHinting()                                             */
/*---------------------------------------------------------------------*/
/**
 *  @returns {boolean} the current pixel hinting state.
 */
DvtSvgDisplayable.prototype.getPixelHinting = function () {
  return this._pixelHinting;
};

/**
 * Enables/disables pixel hinting.
 * @param {boolean}  bHint  true if pixel hinting should be interpreted/applied by the
 * implementation platform.
 */
DvtSvgDisplayable.prototype.setPixelHinting = function (bHint) {
  this._pixelHinting = bHint ;
  if (bHint) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'shape-rendering', 'crispEdges') ;
  }
  else {
    DvtSvgUtils.removeAttrNullNS(this._elem, 'shape-rendering') ;
  }
};

/*---------------------------------------------------------------------*/
/*   get/setVisible()                                                  */
/*---------------------------------------------------------------------*/
/**
  *  Gets the visibility of this object.
  *  @returns {boolean}  True if the object is visible, else false.
  */
DvtSvgDisplayable.prototype.getVisible = function()
{
   return this._bVisible ;
};

/**
  *  Enables/disables the visibility of this object.
  *  @param {boolean}  bVis  True if the object is to be visible, else false if
  *  it is to be hidden.
  */
DvtSvgDisplayable.prototype.setVisible = function(bVis)
{
   if (this._bVisible !== bVis) {
     this._bVisible = bVis ;
     var elem = (this instanceof DvtSvgMarker) ? this._elem : this.getElem();

     //Bug 16005714 - HTML5: VISIBILITY="VISIBLE" LEFT ON ELEMENT AFTER ANIMATION
     //Since the default value for visibility is true, just remove the 'visibility' attribute.
     //This change is needed to avoid the attribute visibility="visible" left on
     //this element after animation.
     //Note: in SVG, the visibility attribute doesn't behave like Flash, 
     //Ex: if a child has visibility="visible" and its container has visibility=hidden
     //the child is still visible
     if (bVis) {
       DvtSvgUtils.removeAttrNullNS(elem, 'visibility');
     }
     else {
       DvtSvgUtils.setAttrNullNS(elem, 'visibility', 'hidden') ;
     }
   }

};


/*---------------------------------------------------------------------*/
/*   setClipPath()                                                     */
/*---------------------------------------------------------------------*/
/**
 *  Sets a clipping region for this object.
 *  @param {DvtGraphClipPath}  cp  the DvtGraphClipPath object specifying the clipping region.
 */
DvtSvgDisplayable.prototype.setClipPath = function(cp) {
  // Bug 14764452 - PANELCARDS NOT CLIPPING IN DIAGRAM
  // if cp is null, clear the clip-path property, 
  // ideally the clipPath should also be removed from the global defs
  // if it's not used.
  if (! cp) {
    DvtSvgUtils.removeAttrNullNS(this.getOuterElem(), 'clip-path');
    return;
  }

  // Create an outer group if there is a matrix defined, since SVG applies transforms before clip paths.
  if(!this._outerElem && this._matrix)
    this._createOuterGroupElem();

  var id = cp.getId() ;
  if (id) {     // essential to have an id to reference
    var context  = this.getObj().getCtx() ;

    if (DvtSvgShapeUtils.addClipPath(cp, context))  {    // add to global defs
      // Set the clip path on the outer element of the shape
      DvtSvgUtils.setAttrNullNS(this.getOuterElem(), 'clip-path', 'url(#' + id + ')');
    }
  }    
};

DvtSvgDisplayable.prototype.addClipPath = function(cp, context) {
    return DvtSvgShapeUtils.addClipPath(cp, context);
}

/**
 * Returns the bounds of the displayable relative to its coordinate space.
 * @return {DvtRectangle} The bounds of the displayable relative to its coordinate space.
 */
DvtSvgDisplayable.prototype.getDimensions = function() {
  try {
     var bbox = this.getElem().getBBox();
  } catch(e) {
     return null;
  }
  //don't return bbox directly because we don't want calling code
  //to depend on platform-specific API, so instead turn it into 
  //a DvtRectangle
  return new DvtRectangle(bbox.x, bbox.y, bbox.width, bbox.height);
};

//BUG FIX 13842194:
/**
 * Returns the bounds of the displayable relative to its coordinate space,
 * including its stroke width.
 * @return {DvtRectangle} The bounds of the displayable relative to its coordinate space, including its stroke width.
 */
DvtSvgDisplayable.prototype.getDimensionsWithStroke = function() {
  return this.GetDimensionsWithStroke();
};

//BUG FIX 13842194:
DvtSvgDisplayable.prototype.GetDimensionsWithStroke = function(targetCoordinateSpace) {
  //get dims for the shape elem, and change coord space if necessary
  var dims = this.GetElemDimensionsWithStroke();
  if (!targetCoordinateSpace || targetCoordinateSpace === this.getObj())
    return dims;
  else { // Calculate the bounds relative to the target space
    return this.getObj().ConvertCoordSpaceRect(dims, targetCoordinateSpace);
  }
};

//BUG FIX 13842194:
DvtSvgDisplayable.prototype.GetElemDimensionsWithStroke = function() {
  var bbox = null;
  try {
    //always use this._elem, which should point to a concrete shape element
    bbox = this._elem.getBBox();
  } catch(e) {
    return null;
  }
  //don't return bbox directly because we don't want calling code
  //to depend on platform-specific API, so instead turn it into 
  //a DvtRectangle
  return new DvtRectangle(bbox.x, bbox.y, bbox.width, bbox.height);
};

/**
 * Returns true if any of the specified attribute names are present on the element.
 * @param {object} elem  The SVG DOM element.
 * @param {array} attrNames The array of attribute names to look for.
 * @protected
  */
DvtSvgDisplayable.HasAttributes = function(elem, attrNames) {
  if (attrNames)
  {
    var numAttrs = attrNames.length;
    for (var i = 0; i < numAttrs; i++)
    {
      if(DvtSvgUtils.getAttrNullNS(elem, attrNames[i]))
        return true;
    }
  }
  return false;
}

/**
 * Transfer relevant attributes from the original SVG DOM element to the new SVG DOM element.
 * @param {object} fromElem  The SVG DOM element.
 * @param {object} toElem  The new SVG DOM element.
 * @param {array} attrNames The array of attribute names to transfer.
 * @protected
  */
DvtSvgDisplayable.TransferAttributes = function(fromElem, toElem, attrNames)
{
  if (attrNames)
  {
    var attrName;
    var attrValue;
    var numAttrs = attrNames.length;
    for (var i = 0; i < numAttrs; i++)
    {
      attrName = attrNames[i];
      attrValue = DvtSvgUtils.getAttrNullNS(fromElem, attrName);
      if (attrValue)
      {
        DvtSvgUtils.removeAttrNullNS(fromElem, attrName);
        DvtSvgUtils.setAttrNullNS(toElem, attrName, attrValue);
        if (DvtAgent.isPlatformIE()) { // bug 14605036, prev removeAttributeNS()
          DvtSvgUtils.setAttrNullNS(fromElem, attrName, null);                 // fails for IE9 (9.0.8112.16421)
        }
      }
    }
  }
};

/**
 * Creates an outer group element to workaround issues with filters and clip paths.
 * @private
 */
DvtSvgDisplayable.prototype._createOuterGroupElem = function()
{
  if(this._outerElem) 
    return;
    
  var outerId = this._id ? this._id + '_outer' : null;  
  this._outerElem = DvtSvgShapeUtils.createElement('g', outerId);
    
  // Reparent the DOM elements
  var parent = this.getParent();
  if(parent) {
    var parentElem = parent.getImpl().getElem();
    parentElem.replaceChild(this._outerElem, this.getElem());
  }
  DvtSvgUtils.appendChildElem(this._outerElem, this.getElem());
  
  // Transfer attributes from the old outermost SVG element to the new outer element
  DvtSvgDisplayable.TransferAttributes(this.getElem(), this._outerElem, DvtSvgDisplayable._ATTRS_TRANSFERABLE_TO_OUTER)
}

/*---------------------------------------------------------------------*/
/*   Event Handling Support                                            */
/*---------------------------------------------------------------------*/

/**
 * Adds an event listener.
 * @param {String} type the event type
 * @param {String} useCapture whether the listener operates in the capture phase
 */
DvtSvgDisplayable.prototype.addListener = function(type, useCapture) {
  var listener = this._getListener(useCapture);
  // on keyboard events, add the listener to the component's wrapping div, since SVG 
  // DOM elements don't support keystrokes. 
  if(type == DvtKeyboardEvent.KEYUP || type == DvtKeyboardEvent.KEYDOWN)
  {
    if(this.getObj())
    {
      var context = this.getObj().getCtx();
      var stage = context.getStage();
      var wrappingDiv = stage.getImpl().getSVGRoot().parentNode;
      // allow support for multiple displayables to receive keyboard events
      // TODO: replace this with a singular compound event manager that
      //       will dispatch keyboard events to individual event managers
      if(!wrappingDiv._obj)
      {
        wrappingDiv._obj = []
      }
      if(DvtArrayUtils.getIndex(wrappingDiv._obj, this) == -1)
      {
        wrappingDiv._obj.push(this);
      }
      listener = DvtHtmlKeyboardListenerUtils.getListener(useCapture);
      DvtSvgUtils.addDomEventListener(wrappingDiv, type, listener, useCapture);
    }
  }
  else 
  {
    this.AddElemListener(type, listener, useCapture);
  }
}

DvtSvgDisplayable.prototype.AddElemListener = function(type, listener, useCapture) {
  DvtSvgUtils.addDomEventListener(this.getElem(), type, listener, useCapture);
  if (type == DvtTouchEvent.TOUCHEND) {
      DvtSvgUtils.addDomEventListener(this.getElem(), DvtTouchEvent.TOUCHCANCEL, listener, useCapture);
  }
};

/**
 * Removes an event listener.
 * @param {string} type the event type
 * @param {function} listener the function to call
 * @param {String} useCapture whether the listener operates in the capture phase
 */
DvtSvgDisplayable.prototype.removeListener = function(type, useCapture) {
  var listener = this._getListener(useCapture);
  if(type == DvtKeyboardEvent.KEYUP || type == DvtKeyboardEvent.KEYDOWN)
  {
    if(this.getObj())
    {
      var context = this.getObj().getCtx();
      var stage = context.getStage();
      var wrappingDiv = stage.getImpl().getSVGRoot().parentNode;
      DvtSvgUtils.removeDomEventListener(wrappingDiv, type, listener, useCapture);
      var index = DvtArrayUtils.getIndex(wrappingDiv._obj, this);
      if(index !== -1)
      {
        wrappingDiv._obj.splice(index);
      }
    }
  }
  else 
  {
    DvtSvgUtils.removeDomEventListener(this.getElem(), type, listener, useCapture);
  }
}

// TODO JSdoc
DvtSvgDisplayable.prototype._getListener = function(useCapture) {
  var thisRef = this;
  if(useCapture) {
    if (!this._captureClosure) {
      this._captureClosure = function (event) {
        thisRef._captureListener(event);
      };
    }
    return this._captureClosure;
  }
  else {
    if (!this._bubbleClosure) {
      this._bubbleClosure = function (event) {
        thisRef._bubbleListener(event);
      };
    }
    return this._bubbleClosure;
  }
}

/**
 * The event listener that is called by the implementation object's bubble phase listeners.
 * This function will wrap the event and delegate to the real event listeners.  
 * @param {object} event the DOM event object
 * @this {object} the platform object actively processing the event object with an event listener
 * @private
 */
DvtSvgDisplayable.prototype._bubbleListener = function(event) {
  if (DvtAgent.isPlatformIE()) {
      // Moving an object in the dom for IE causes mouse over events to fire if the moved item is under the mouse
      // Ensure mouse over is not repeatedly called in such a case
      if (event.type == DvtMouseEvent.MOUSEOVER) {
          if (this._bubbleHoverItem) {
              if (this._bubbleHoverItem == event.target) {
                  // Prevent infinite loop
                  return;
              } else {
                  //MOUSEOVER event on a DOM element stores the element in _bubbleHoverItem and MOUSEOUT event clears _bubbleHoverItem.
                  //If a MOUSEOVER event is not followed by MOUSEOUT event, _bubbleHoverItem won't be cleared.
                  //During the subsequent MOUSEOVER event if the event target is different than _bubbleHoverItem, 
                  //that indicates the browser have missed to fire MOUSEOUT event for previous DOM element stored in _bubbleHoverItem.
                  //So building a new MOUSEOUT event for _bubbleHoverItem.
                  var dvtEvent = DvtSvgEventFactory.newEvent(event, this.getObj().getCtx());
                  //Bug 17369581: Set the event as MOUSEOUT event, target as _bubbleHoverItem, relatedTarget as event.target
                  //This is equivalent to firing new MOUSEOUT event for _bubbleHoverItem
                  dvtEvent.modifyEventForIE(DvtMouseEvent.MOUSEOUT, this._bubbleHoverItem);
                  this.getObj().FireListener(dvtEvent, false);
              }
          }
          this._bubbleHoverItem = event.target;
      } else if (event.type == DvtMouseEvent.MOUSEOUT) {
          this._bubbleHoverItem = null;
      }
  }

  var dvtEvent = DvtSvgEventFactory.newEvent(event, this.getObj().getCtx());
  this.getObj().FireListener(dvtEvent, false);
}

/**
 * The event listener that is called by the implementation object's capture phase listeners.
 * This function will wrap the event and delegate to the real event listeners.  
 * @param {object} event the DOM event object
 * @this {object} the platform object actively processing the event object with an event listener
 * @private
 */
DvtSvgDisplayable.prototype._captureListener = function(event) {
  if (DvtAgent.isPlatformIE()) {
      // Moving an object in the dom for IE causes mouse over events to fire if the moved item is under the mouse
      // Ensure mouse over is not repeatedly called in such a case
      if (event.type == DvtMouseEvent.MOUSEOVER) {
          if (this._captureHoverItem) {
              if (this._captureHoverItem == event.target) {
                  // Prevent infinite loop
                  return;
              } else {
                  //MOUSEOVER event on a DOM element stores the element in _captureHoverItem and MOUSEOUT event clears _captureHoverItem.
                  //If a MOUSEOVER event is not followed by MOUSEOUT event, _captureHoverItem won't be cleared.
                  //During the subsequent MOUSEOVER event if the event target is different than _captureHoverItem, 
                  //that indicates the browser have missed to fire MOUSEOUT event for previous DOM element stored in _captureHoverItem.
                  //So building a new MOUSEOUT event for _captureHoverItem.
                  var dvtEvent = DvtSvgEventFactory.newEvent(event, this.getObj().getCtx());
                  //Bug 17369581: Set the event as MOUSEOUT event, target as _captureHoverItem, relatedTarget as event.target
                  //This is equivalent to firing new MOUSEOUT event for _captureHoverItem
                  dvtEvent.modifyEventForIE(DvtMouseEvent.MOUSEOUT, this._captureHoverItem);
                  this.getObj().FireListener(dvtEvent, true);
              }
          }
          this._captureHoverItem = event.target;
      } else if (event.type == DvtMouseEvent.MOUSEOUT) {
          this._captureHoverItem = null;
      }
  }
  var dvtEvent = DvtSvgEventFactory.newEvent(event, this.getObj().getCtx());
  this.getObj().FireListener(dvtEvent, true);
}


/*-------------------------------------------------------------------------*/
/*   CSS Style Support                                                     */
/*-------------------------------------------------------------------------*/

/**
 * @returns {DvtCssStyle} the DvtCSSStyle of this object.
 */ 
DvtSvgDisplayable.prototype.getCSSStyle = function()
{
  return this._cssStyle;
}

/**
 * Sets the DvtCSSStyle of this object.
 * @param {DvtCssStyle} style The DvtCSSStyle of this object.
 */
DvtSvgDisplayable.prototype.setCSSStyle = function(style)
{
  this._cssStyle = style;
}


/**
 * Sets the cursor on this object.
 * @param {String} cursor type
 */
DvtSvgDisplayable.prototype.setCursor = function(cursorType)
{
  this._cursor = cursorType;
  if (cursorType)
  {
    DvtSvgUtils.setAttrNullNS(this.getElem(), "cursor", cursorType);
  }
  else
  {
    DvtSvgUtils.removeAttrNullNS(this.getElem(), "cursor");
  }
};


/**
 * Gets the cursor used on this object.
 * @type {String}
 */
DvtSvgDisplayable.prototype.getCursor = function()
{
  return this._cursor;
};


/**
 * Sets whether mouse events are enabled on this object.
 * @param {boolean} whether mouse events are enabled
 */
DvtSvgDisplayable.prototype.setMouseEnabled = function(bEnabled)
{
  this._bMouseEnabled = bEnabled;
  var val;
  if (bEnabled)
  {
    val = "visiblePainted";
  }
  else
  {
    val = "none";
  }
  DvtSvgUtils.setAttrNullNS(this.getElem(), "pointer-events", val);
};
    

/**
 * Gets whether mouse events are enabled on this object.
 * @type {boolean}
 */
DvtSvgDisplayable.prototype.isMouseEnabled = function()
{
  return this._bMouseEnabled;
};


/*---------------------------------------------------------------------*/
/*   get/setAlpha()                                                    */
/*---------------------------------------------------------------------*/
/**
  *  Returns the alpha channel value.
  *  @type number  
  *  @returns A value between 0 (invisible) and 1 (opaque).
  */
DvtSvgDisplayable.prototype.getAlpha = function()
{
   return this._alpha;
};

/**
  *  Sets the alpha.
  *  @param {number} alpha  A value between 0 (invisible) and 1 (opaque).
  *  @returns nothing
  */
DvtSvgDisplayable.prototype.setAlpha = function(alpha)
{
   //when animating alpha, small values are turned into strings like
   //"3.145e-8", which SVG incorrectly clamps to 1, so just cut off
   //small values here and make them 0
   if (alpha < 0.00001)
     alpha = 0;
   
   if (alpha !== this._alpha)
   {
     this._alpha = alpha;
     DvtSvgUtils.setAttrNullNS(this.getElem(), 'opacity', this._alpha) ;
   }
};



/**
  *   Set the matrix object to use to transform this container.
  *   @param {DvtMatrix} mat  The matrix object to apply.
  */
DvtSvgDisplayable.prototype.setMatrix = function(mat)
{
  // Create an outer elem if needed
  if(!this._outerElem && DvtSvgDisplayable.HasAttributes(this.getElem(), DvtSvgDisplayable._ATTRS_TRANSFERABLE_TO_OUTER)) 
    this._createOuterGroupElem();

  this._matrix = mat ;
  //apply the new matrix if it's non-null
  if (mat)
  {
    var sMat = 'matrix(' + mat.getA() + ',' + mat.getC() + ',' + mat.getB() + ',' + mat.getD() + ',' + mat.getTx() + ',' + mat.getTy() + ')';
    
    //set the transform attribute on the outer SVG element of this shape
    this.SetElemMatrix(sMat);
    //set the vector-effect attribute to prevent the stroke-width
    //from scaling with the transform
    //NOTE: this is commented out for now because it causes strange rendering
    //artifacts when scaling to a small value
    //DvtSvgUtils.setAttrNullNS(this.getElem(), 'vector-effect', 'non-scaling-stroke') ;
  }
  //if clearing the existing matrix by setting a null or undefined mat,
  //then remove the existing attribute from the DOM
  else
  {
    var transformAttr = DvtSvgUtils.getAttrNullNS(this.getElem(), 'transform');
    if (transformAttr)
    {
      DvtSvgUtils.removeAttrNullNS(this.getElem(), 'transform');
      if (DvtAgent.isPlatformIE()) { // bug 14617946, prev removeAttributeNS()
        DvtSvgUtils.setAttrNullNS(this.getElem(), 'transform', null);        // fails for IE9 (9.0.8112.16421)
      }

    }
    //NOTE: this is commented out for now because it causes strange rendering
    //artifacts when scaling to a small value
    var vectorEffectAttr;// = DvtSvgUtils.getAttrNullNS(this.getElem(), 'vector-effect');
    if (vectorEffectAttr)
    {
      DvtSvgUtils.removeAttrNullNS(this.getElem(), 'vector-effect');
    }
  }
};


DvtSvgDisplayable.prototype.SetElemMatrix = function(sMat) {
  DvtSvgUtils.setAttrNullNS(this.getElem(), 'transform', sMat) ;
};


DvtSvgDisplayable.prototype.applyDrawEffects = function(effects)
{
  // Create an outer group if there is a matrix defined, since SVG applies transforms before filters.
  if(!this._outerElem && this._matrix)
    this._createOuterGroupElem();

  //remove current filter
  if (this._filter)
  {
    DvtSvgUtils.removeAttrNullNS(this.getOuterElem(), 'filter');
    this.getObj().getCtx().removeDefs(this._filter);
    this._filter = null;
  }
  
  //add new filter if necessary
  if (effects && effects.length > 0)
  {
    //Bug 12394679: Repaint bug in Firefox requires us to force a repaint after removing filter
    //At worst we will create n empty filters where n=# markers
    this._filter = DvtSvgFilterUtils.createFilter(effects, this);
    if (this._filter) {
        this.getObj().getCtx().appendDefs(this._filter);
        var filterId = DvtSvgUtils.getAttrNullNS(this._filter, 'id');
        DvtSvgUtils.setAttrNullNS(this.getOuterElem(), 'filter', 'url(#' + filterId + ')');
    }
  }
  
};


/**
 * Sets the WAI-ARIA role.
 * @param {String} role The role attribute value.
 */
DvtSvgDisplayable.prototype.setAriaRole = function(role) {
  if (role)
    DvtSvgUtils.setAttrNullNS(this.getElem(), 'role', role);
  else
    DvtSvgUtils.removeAttrNullNS(this.getElem(), 'role');
}

/**
 * Sets the WAI-ARIA property/state.
 * @param {String} property The property/state attribute name. The prefix "aria-" should be skipped.
 * @param {String} value The property/state attribute value.
 */
DvtSvgDisplayable.prototype.setAriaProperty = function(property, value) {
  if (value)
    DvtSvgUtils.setAttrNullNS(this.getElem(), 'aria-' + property, value);
  else
    DvtSvgUtils.removeAttrNullNS(this.getElem(), 'aria-' + property);
}


/**
 * Convert a point from stage coords to local coords.
 * @param {DvtPoint}  point  point in stage coords
 * @type DvtPoint
 */
DvtSvgDisplayable.prototype.stageToLocal = function(point)
{
   var displayable = this.getObj();
   var pathToStage = displayable.getPathToStage();
   var mat;
   var retPoint = point;
   for (var i = pathToStage.length - 1; i >= 0; i--)
   {
      displayable = pathToStage[i];
      mat = displayable.getMatrix().clone();
      mat.invert();
      retPoint = mat.transformPoint(retPoint);
   }
   return retPoint;
};

/**
 * Convert a point from local coords to stage coords.
 * @param {DvtPoint}  point  point in local coords
 * @type DvtPoint
 */
DvtSvgDisplayable.prototype.localToStage = function(point)
{
   var displayable = this.getObj();
   var pathToStage = displayable.getPathToStage();
   var mat;
   var retPoint = point;
   for (var i = 0; i < pathToStage.length; i++)
   {
      displayable = pathToStage[i];
      mat = displayable.getMatrix();
      retPoint = mat.transformPoint(retPoint);
   }
   return retPoint;
};

/**
 * Creates a copy of the svg content in the specified container
 * 
 * @param {DvtContainer} container the container for the copied content
 */
DvtSvgDisplayable.prototype.createCopy = function(container) 
{
   var clonedSvg = this.getElem().cloneNode(true);
   DvtSvgUtils.appendChildElem(container.getImpl().getElem(), clonedSvg);
   this._disableEvents(clonedSvg);

   //Bug 16005714 - HTML5: VISIBILITY="VISIBLE" LEFT ON ELEMENT AFTER ANIMATION
   //This is a potential backup for the real fix in setVisible.
   //when this method is called to perform a whole "node" transition for panelCard
   //the "visibility" attribute on this clone element can never be turned on/off later
   //need to move this attribute to the clonedContainer now
   /*
   var vis = DvtSvgUtils.getAttrNullNS(clonedSvg, "visibility");
   if (vis) {
     DvtSvgUtils.removeAttrNullNS(clonedSvg, "visibility") ;
     DvtSvgUtils.setAttrNullNS(container.getImpl().getElem(), 'visibility', vis);
   }
   */
}

DvtSvgDisplayable.prototype._disableEvents = function(svgElem) 
{
   var child = svgElem.firstChild;
    //loop over all children
    while (child != null) {
        if (child.setAttributeNS) {
            DvtSvgUtils.setAttrNullNS(child, "pointer-events", "none");
            DvtSvgUtils.setAttrNullNS(child, "id", null);
        }
        this._disableEvents(child);
        child = child.nextSibling;
    }
}

/**
 * Dispatch event
 * @param {String} eventType
 * @param {String} params An optional parameter to specify other parameters for the event
 */
DvtSvgDisplayable.prototype.dispatchDisplayableEvent = function(eventType, params) 
{
    var createEventType = DvtSvgDisplayable._CREATE_EVENT_TYPE_MAP[eventType];
    var context;
    if (DvtMouseEvent.CLICK == createEventType ||
        DvtMouseEvent.MOUSEOVER == createEventType ||
        DvtMouseEvent.MOUSEOUT == createEventType ||
        DvtMouseEvent.MOUSEMOVE == createEventType) {
        if (document.createEvent) {
            context = this.getObj().getCtx();
            var dim = this.getObj().getDimensions();
            var elementPosition = this.getObj().localToStage(new DvtPoint(dim.x, dim.y));
            var absoluteStagePos = context.getStageAbsolutePosition();
            var absoluteElementPosition = new DvtPoint(absoluteStagePos.x + elementPosition.x, absoluteStagePos.y + elementPosition.y);
            var event = document.createEvent("MouseEvents");
            event.initMouseEvent(createEventType, true, true, window, 1, absoluteElementPosition.x, absoluteElementPosition.y, absoluteElementPosition.x, absoluteElementPosition.y, false, false, false, false, 0, null);
            this.getElem().dispatchEvent(event);
        }
    }
    else if (DvtKeyboardEvent.KEYDOWN == createEventType ||
             DvtKeyboardEvent.KEYUP == createEventType) {
      if (document.createEvent) {
        var keyboardEvent = document.createEvent("KeyboardEvent");
        var keycode = parseInt(params);
        
        if(this._ctrlKeyPressed === undefined)
          this._ctrlKeyPressed = false;

        if(this._shiftKeyPressed === undefined)
          this._shiftKeyPressed = false;
        
        if(keycode == DvtKeyboardEvent.CONTROL) {
          if(this._ctrlKeyPressed && createEventType == DvtKeyboardEvent.KEYUP)
            this._ctrlKeyPressed = false;
          else if(!this._ctrlKeyPressed && createEventType == DvtKeyboardEvent.KEYDOWN)
            this._ctrlKeyPressed = true;
        } 
        else if(keycode == DvtKeyboardEvent.SHIFT) {
          if(this._shiftKeyPressed && createEventType == DvtKeyboardEvent.KEYUP)
            this._shiftKeyPressed = false;
          else if(!this._shiftKeyPressed && createEventType == DvtKeyboardEvent.KEYDOWN)
            this._shiftKeyPressed = true;
        }
          
        
        if (typeof(keyboardEvent.initKeyboardEvent) != 'undefined') {
          keyboardEvent.initKeyboardEvent(createEventType, true, true, window, this._ctrlKeyPressed, false, this._shiftKeyPressed, false, keycode, keycode);
        } else {
          keyboardEvent.initKeyEvent(createEventType, true, true, window, this._ctrlKeyPressed, false, false, this._shiftKeyPressed, keycode, keycode);
        }        
      
        /*      
        ideally, we would just create the native keyboard event and disptach it to the wrapping div, but we
        can't for two reasons
        1. when the keyboardEvent is initialized above, the initKeyboardEvent method used by Webkit doesn't initialize
           the event with the right keycode; it is always 0.  This is a known bug tracked in Chromium and at Webkit
           see http://code.google.com/p/chromium/issues/detail?id=27048 (Chromium) and
           https://bugs.webkit.org/show_bug.cgi?id=16735 (Webkit)
        2. since the native event doesn't work, I tried dispatching a DvtSvgKeyboardEvent to the wrapping div.
           however, this generates a DOM EventException of type UNSPECIFIED_EVENT_TYPE_ERR, even though the
           type of the DvtSvgKeyboardEvent was specified.
        
        So, instead, we will directly call the bubble listener that we attach to the wrapping div 
        */
        
        var svgKeyboardEvent = DvtSvgEventFactory.newEvent(keyboardEvent);
        svgKeyboardEvent.keyCode = keycode;
        svgKeyboardEvent.ctrlKey = this._ctrlKeyPressed;
        svgKeyboardEvent.shiftKey = this._shiftKeyPressed;
      
        if(this.getObj()) {
          context = this.getObj().getCtx();
          var stage = context.getStage();
          var wrappingDiv = stage.getImpl().getSVGRoot().parentNode;
          DvtHtmlKeyboardListenerUtils._bubbleListener.call(wrappingDiv, svgKeyboardEvent);
        }
      }
    }
}

/**
 * Sets/adds desc element to the SVG node.
 * @param {String} descTxt The description value.
 */
DvtSvgDisplayable.prototype.setDesc = function(descTxt) {
  if (!descTxt || this._desc == descTxt)
    return;
    
  if (!this._desc) // new element
    this._createDesc(descTxt);    
  else if (this._desc != descTxt) { // replace existing
    var isFound = false;    
    // loop over all children
    var child = this.getElem().firstChild;    
    while (child != null) {    
      if (child.tagName == 'desc') {
        var textNode = child.firstChild;        
        if (textNode)
          textNode.nodeValue = descTxt;
        
        this._desc = descTxt;
        isFound = true;  
        break;
      }    
      child = child.nextSibling;
    }
    if (!isFound)
      this._createDesc(descTxt);
  }
}

/**
 * Adds desc element to the SVG node.
 * @param {String} descTxt The description value.
 */
DvtSvgDisplayable.prototype._createDesc = function(descTxt) {
  if (!descTxt)
    return;

  var descElem  = DvtSvgShapeUtils.createElement("desc", null);
  var textNode = document.createTextNode(descTxt);
  DvtSvgUtils.appendChildElem(descElem, textNode);
  DvtSvgUtils.appendChildElem(this.getElem(), descElem);
  this._desc = descTxt;
}

/**
 * Dispatches the native event to the internal dom element
 * Note: Use with caution
 * @param {Object} event
 * @override
 */
DvtSvgDisplayable.prototype.dispatchNativeEvent = function(event) 
{
}
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*  DvtSvgContainer         SVG implementation of DvtContainer         */
/*---------------------------------------------------------------------*/
/**  SVG implementation of DvtContainer.
  *  @extends DvtSvgDisplayable
  *  @class DvtSvgContainer
  *  @constructor  
  *  @param {String} id   An optional id for this object.
  *  @param {String} type  The SVG DOM element type.
  */ 
var   DvtSvgContainer = function(id, type)
{
  this._Init(id, type) ; 
};

DvtObj.createSubclass(DvtSvgContainer, DvtSvgDisplayable, "DvtSvgContainer") ;

/**
  * @protected
  * Array of SVG attributes that should be transferred from the shape
  * tag to the group when this shape becomes a group (when children
  * are added to it).
  */
DvtSvgContainer.AttributesTransferableToGroup = ['transform', 'opacity', 'style', 'visibility', 'pointer-events', 'clip-path'];


/*---------------------------------------------------------------------*/
/*   addChild()           Add a child to this container                */
/*---------------------------------------------------------------------*/
/**
  *   Adds the specifed object as a child of this container.  The object is
  *   added to the end of the child list.
  *   @param {DvtSvgDisplayable} obj The object to be added.
  */
DvtSvgContainer.prototype.addChild = function(obj)
{

  if (this._bShapeContainer) {
    //  This is a shape "container".
    //  If no previous children, will create a group DOM element for the this
    //  (parent) object and add the new child to the child group DOM element.
    //  else will add the object directly to the shape group container element.

    this.CreateChildGroupElem(false);
  }

  //  Bug 15865017 - GET RID OF DVTGOLINK AND IMPLS
  //  if there is an anchor elem <a> for this container
  //  append child to the <a> element 
  //  otherwise append child directly to this container group element

  var containerElem = this.getContainerElem();
  DvtSvgUtils.appendChildElem(containerElem, obj.getOuterElem());

} ;

/**
  *   Adds the specified object as a child of this container at the specified index. Returns
  *   immediately if the index position doesn't already exist in the child list.  If a currently
  *   occupied index is specified, the current child at that position and all subsequent children
  *   are moved one position higher in the list.
  *   @param {DvtSvgDisplayable} obj The object to be added.
  *   @param {number} index The index at which to add this object
  */
DvtSvgContainer.prototype.addChildAt = function(obj, index)
{
  var idx = index;

  if (this._bShapeContainer) {
    //  This is a shape "container".
    //  If no previous children, will create a group DOM element for the this
    //  (parent) object and add the new child to the child group DOM element.
    //  else will add the object directly to the shape group container element.
    this.CreateChildGroupElem(false);

    //need to increment the index to account for the shape dom element,
    //which should be the first child of the childGroupElem
    idx++;
  }

  //  Bug 15865017 - GET RID OF DVTGOLINK AND IMPLS
  //  if there is an anchor elem <a> for this container
  //  append child to the <a> element 
  //  otherwise append child directly to this container group element

  var containerElem = this.getContainerElem();
  var existingNode = containerElem.childNodes[idx];
  // BUG #12661320: IE9 cannot handle a value of undefined in insertBefore.  Set to null in such a case. 
  if (!existingNode)
    existingNode = null;
  containerElem.insertBefore(obj.getOuterElem(), existingNode);
}

/**
 * Returns an rray of SVG attributes that should be transferred from the shape
 * tag to the group when this shape becomes a group (when children are added to it).
 * @return {array}
 */
DvtSvgContainer.prototype.GetAttributesTransferableToGroup = function() {
  return DvtSvgContainer.AttributesTransferableToGroup;
}

/*---------------------------------------------------------------------*/
/*   addChildAfter()                                                   */
/*---------------------------------------------------------------------*/
/**
  *   Adds the specifed object as a child of this container after a specific
  *   object in the child list.
  *   @param {Object} obj  The object to be added.
  *   @param {Object} objAfter  The object after which the new child is to be added.
  */
DvtSvgContainer.prototype.addChildAfter = function(obj, objAfter)
{
     // To Do  JRM
} ;


/*---------------------------------------------------------------------*/
/*  addChildBefore()                                                   */
/*---------------------------------------------------------------------*/
/**
  *   Adds the specifed object as a child of this container before a specific
  *   object in the child list.
  *   @param {Object} obj  The object to be added.
  *   @param {Object} objBefore  The object before which the new child is
  *   to be added.
  */
DvtSvgContainer.prototype.addChildBefore = function(obj, objBefore)
{
     // To Do JRM
} ;




/**
  * @override
  */
DvtSvgContainer.prototype.getElem = function()
{
  return (this._childGroupElem? this._childGroupElem : this._elem) ;
} ;

/*---------------------------------------------------------------------*/
/*   _Init()                                                           */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtSvgContainer.prototype._Init = function(id, type)
{
  // For the SVG implementation, we need to know whether this is a standard
  // non-shape container, or a shape "container".  Since elementary objects
  // may not be nested, e.g. a rect containing another rect, an artificial 
  // group must be constructed to group the parent and the children.  That
  // is they actually become grouped siblings.


  this._bShapeContainer = (this instanceof DvtSvgShape) ;  // if shape "container"

  DvtSvgContainer.superclass._Init.call(this, id, type) ;

  this._childGroupElem  = null ;       // child surround group
} ;


/*---------------------------------------------------------------------*/
/*    removeChild()                                                    */
/*---------------------------------------------------------------------*/
/**
  *   Removes the specified child object from this container.
  *   @param {DvtSvgDisplayable} obj The object to be removed.
  */
DvtSvgContainer.prototype.removeChild = function(obj)
{
   var elemObj  = obj.getOuterElem() ;  // obj's outer DOM element
   var parent   = obj.getParent() ;     // get parent object (the container
                                        // or the shape group container)
   if (elemObj && parent) {
     // Bug 15865017 - GET RID OF DVTGOLINK AND IMPLS
     var elem = this.getContainerElem();
     elem.removeChild(elemObj) ;
   }

   //  If no more children, can remove the added group for child containership,
   //  and reparent the containing shape directly back to its parent in the
   //  position that the added child group container occupied.

   // Bug 15865017 - GET RID OF DVTGOLINK AND IMPLS
   // don't remove the childGroupElem because we need it to hold the anchor
   if (! this._anchorElem && this._bShapeContainer && this.getObj().getNumChildren() === 1) {
     var  childGroupElem       = this._childGroupElem ;
     var  childGroupElemParent = (childGroupElem? childGroupElem.parentNode : null);
     
     if (childGroupElemParent) {
      DvtSvgDisplayable.TransferAttributes(childGroupElem, this._elem, this.GetAttributesTransferableToGroup());     
       childGroupElemParent.replaceChild(this._elem, childGroupElem) ;
       this._childGroupElem = null ;
     }
   }
} ;



/*---------------------------------------------------------------------*/
/*    swap()                                                           */
/*---------------------------------------------------------------------*/

//  In progress  TDO  JRM

/**
  *    Exchanges the positions of two objects in this container..
  */ 
DvtSvgContainer.prototype.swap = function(obj1, obj2)
{
   //  Update the DOM

   var elem1     = obj1.getElem() ;      // obj's DOM element
   var elem2     = objw.getElem() ;
   var parent    = obj1.getParent() ;    // get parent object (the container
                                         // or the shape group container)
   var elem2Next = elem2.nextSibling;

   if (parent && elem1 && elem2) {
     parent.replaceChild(elem1, elem2) ;
     parent.insertBefore(elem1, elem2Next) ;

     // Update the array

     var idx1 = obj1.getIndex() ;
     var idx2 = obj2.getIndex() ;

     this._arList[idx1] = obj2 ;
     this._arList[idx2] = obj1 ;
   }
};

/**
 * Create a group element for adding children.
 * @param {boolean} rmChildren True if all children should be removed
 * @param {boolean} forced True always create a child group element for shape container
 * @protected
 */
DvtSvgContainer.prototype.CreateChildGroupElem = function(rmChildren, forced)
{
  //  This is a shape "container".
  //  If no previous children, will create a group DOM element for the this
  //  (parent) object and add the new child to the child group DOM element.
  //  else will add the object directly to the shape group container element.

  if (! this._childGroupElem && (forced || this.getObj().getNumChildren() === 0)) {
    var childGroupId = this._id ? this._id + '_g' : null;
    this._childGroupElem  = DvtSvgShapeUtils.createElement('g', childGroupId) ;
   
    //  Remove this's DOM element from the parent, and append to child group DOM element.
    var  parent = this.getParent() ;
    var  elemParent ;
    if (parent) {
      elemParent = parent.getImpl().getElem() ;
      elemParent.replaceChild(this._childGroupElem, this._elem) ; 
    }
    if (! rmChildren)
      DvtSvgUtils.appendChildElem(this._childGroupElem, this._elem) ;   // add shape to new group
        
    //transfer attributes from the old outermost SVG element to the
    //new outer group element
    DvtSvgDisplayable.TransferAttributes(this._elem, this._childGroupElem, this.GetAttributesTransferableToGroup());


    //Note need to copy _obj reference to the new group element so that events can be propagated.
    if (this._elem._obj) {
      this._childGroupElem._obj = this._elem._obj;
    }
  }
  else if (rmChildren) {
    this.getObj().removeChildren();
  }

};


//BUG FIX #13641836: setting display='none' causes getDimensions() to 
//throw error in Firefox just like if the element is not on the DOM,
//which in turn breaks several animations
//(leaving this code here, but commented out, as a reference, because
//it was added to fix bug 13511206 in AMX graph)
/**
  *  Enables/disables the visibility of this object.
  *  @param {boolean}  bVis  True if the object is to be visible, else false if
  *  it is to be hidden.
  */
/*DvtSvgContainer.prototype.setVisible = function(bVis)
{
  if (this._bVisible !== bVis) {
      if (this instanceof DvtSvgMarker)
        DvtSvgUtils.setAttrNullNS(this._elem, 'display', bVis? 'inline' : 'none') ;
      else
        DvtSvgUtils.setAttrNullNS(this.getElem(), 'display', bVis? 'inline' : 'none') ;
  }
  DvtSvgContainer.superclass.setVisible.call(this, bVis) ;
};*/


//BUG FIX 13842194:
/**
 * @override
 */
DvtSvgContainer.prototype.getDimensionsWithStroke = function() {
  //a pure container has no shape of its own, so calculate the
  //dims for all child shapes in the subtree rooted at this container
  
  //build an initial array of all direct children of this container
  var ar = [];
  var numChildren = this.getObj().getNumChildren();
  for (var i = 0; i < numChildren; i++) {
    ar.push(this.getObj().getChildAt(i));
  }
  
  //loop over the array of children until it's empty
  var totalDims = null;
  while (ar.length > 0) {
    //remove the first object from the array
    var child = ar.shift();
    //get dims in coordinate space of this container, because we're 
    //processing whole subtree of children under this container
    var dims = child.getImpl().GetDimensionsWithStroke(this.getObj());
    if (dims) {
      if (!totalDims) {
        totalDims = dims;
      }
      else {
        totalDims = totalDims.getUnion(dims);
      }
    }
    
    //add any children of current object to end of array
    numChildren = child.getNumChildren();
    for (var i = 0; i < numChildren; i++) {
      ar.push(child.getChildAt(i));
    }
  }
  return totalDims;
};

//BUG FIX 13842194:
DvtSvgContainer.prototype.GetDimensionsWithStroke = function(targetCoordinateSpace) {
  //pure container doesn't have its own dimensions
  return null;
};


/**
 * Adds a hyperlink to this object, remove the old hyperlink if exists.
 * This method adds a <g> and a <a> tags around this object. <g><a><this element></a></g>
 * @param {DvtObj} linkObj contains destination (url) and targetFrame
 */
DvtSvgContainer.prototype.setHyperlink = function(linkObj) 
{
  var destination;
  var frame;
  var focusable;

  if (linkObj) {
    destination = linkObj["destination"];
    frame = linkObj["targetFrame"];
    focusable = linkObj["focusable"];
  }

  var gElem = this.getElem();
  var aElem;
  var elem = this._elem;

  //if an "a" element already exists, 
  if (this._anchorElem) {
    aElem = this._anchorElem;

    // replace destination and targetFrame
    if (destination) {
      DvtSvgUtils.setAttrNS(aElem, DvtSvgImage.XLINK_NS, 'xlink:href', destination);
      if (frame) {
        DvtSvgUtils.setAttrNullNS(aElem, 'target', frame);
      }
      else {
        DvtSvgUtils.removeAttrNullNS(aElem,'target');
      }
      
      if (focusable)
        DvtSvgUtils.setAttrNullNS(aElem, 'focusable', focusable);
    }

    // no destination, remove "a" element
    else {
      if (gElem && aElem.parentNode == gElem) {
        gElem.removeChild(aElem);
        DvtSvgContainer._reparentChildren(gElem, aElem);
      }
      this.setCursor("default");
      this._anchorElem = null;
    }
  }

  // create an "a" element
  else {
    aElem = DvtSvgShapeUtils.createElement('a');
    if (destination)
      DvtSvgUtils.setAttrNS(aElem, DvtSvgImage.XLINK_NS, 'xlink:href', destination);

    if (frame)
      DvtSvgUtils.setAttrNullNS(aElem, 'target', frame);

    if (focusable)
        DvtSvgUtils.setAttrNullNS(aElem, 'focusable', focusable);

    // need to wrap around shape element (<a><text></a>) with a <g> to avoid
    // dom element replacement error.
    // Bug 15865017 - GET RID OF DVTGOLINK AND IMPLS
    if (this._bShapeContainer) {
      this.CreateChildGroupElem(false, true);
    }

    gElem = this.getElem();    
    DvtSvgContainer._reparentChildren(aElem, gElem);

    DvtSvgUtils.appendChildElem(gElem, aElem);

    this.setCursor(DvtSelectionEffectUtils.getSelectingCursor());
    this._anchorElem = aElem;
  }
};

/*
 * move children from source to target element
 */
DvtSvgContainer._reparentChildren = function(target, source) {
  var childNodes = source.childNodes;

  if (childNodes) {
    var node;
    var lastNode;

    for (var i = childNodes.length - 1; i >= 0; i--) {
      node = childNodes[i];
      if (lastNode) {
        target.insertBefore(node, lastNode);
      }
      else {
        DvtSvgUtils.appendChildElem(target, node);
      }
      lastNode = node;
    }
  }
}

/**
 * Returns the anchor element if exists.
 */
DvtSvgContainer.prototype.getContainerElem = function() {
  return this._anchorElem ? this._anchorElem : this.getElem();
}


/**
 * Dispatches the native event to the internal dom element
 * Note: Use with caution
 * @param {Object} event
 */
DvtSvgContainer.prototype.dispatchNativeEvent = function(event) 
{
  var nativeEvent = event.getNativeEvent();
  var target = null;
  
  if (this._bShapeContainer)
    target = this._childGroupElem;
  else if (this._anchorElem)
    target = this._anchorElem;
  else
    target = this._elem;
    
  if (target.dispatchEvent)
    target.dispatchEvent(nativeEvent);
}
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/* DvtSvgStage()   Contains all objects associated with a specific SVG */
/*                 Root.                                               */
/*---------------------------------------------------------------------*/
/**
 * @constructor
  *  SVG implementation of DvtStage, representing the highest level container
  *  under the &lt;svg&gt; DOM element.
  *  @extends DvtSvgContainer
  *  @class DvtSvgStage
  */
var   DvtSvgStage = function(svgRoot, id)
{
  this._Init(svgRoot, id) ; 
};

DvtObj.createSubclass(DvtSvgStage, DvtSvgContainer, "DvtSvgStage") ;


/*---------------------------------------------------------------------*/
/*  appendDefs()   Append element(s) to the application global <defs>  */
/*                 element.                                            */
/*---------------------------------------------------------------------*/

DvtSvgStage.prototype.appendDefs = function(elem)
{
  DvtSvgUtils.appendChildElem(this._elemDefs, elem) ;
} ;


/*---------------------------------------------------------------------*/
/*   getDefs()        get the application global <defs> DOM element    */
/*---------------------------------------------------------------------*/

DvtSvgStage.prototype.getDefs = function()
{
   return this._elemDefs ;
} ;



/*---------------------------------------------------------------------*/
/*   getSVGRoot()          Returns the SVG root DOM element            */
/*---------------------------------------------------------------------*/

DvtSvgStage.prototype.getSVGRoot = function()
{
   return this._SVGRoot ;
} ;



/*---------------------------------------------------------------------*/
/*   _Init()                                                           */
/*---------------------------------------------------------------------*/
/** @private */
DvtSvgStage.prototype._Init = function(svgRoot, id)
{
  DvtSvgStage.superclass._Init.call(this, id, 'g') ;

  this._SVGRoot   = svgRoot ;   // containing SVG DOM element
  this._bAppended = true ;

  this._obj = null ;            // the controlling Dvt... object
  
  //to disable ability to select text, bug 13453406
  this.disableSelection(this._elem);
  
  //set cursor to default to avoid text cursors on text objects
  this.setCursor("default");
} ;

DvtSvgStage.prototype.disableSelection = function(target){
    target.onselectstart=function(){return false};
    target.onselect=function(){return false};
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.

/*---------------------------------------------------------------------*/
/*   DvtSvgShapeUtils          Static Shape Utility Functions          */
/*---------------------------------------------------------------------*/

/**
 *   Static Shape Utility Functions
 *   @class DvtSvgShapeUtils
 *   @constructor
 */
var  DvtSvgShapeUtils = function()
{} ;

DvtObj.createSubclass(DvtSvgShapeUtils, DvtObj, "DvtSvgShapeUtils");

DvtSvgShapeUtils._uniqueSeed = 0 ;  // for unique Id creation
DvtSvgShapeUtils._Stage      = null ;

/**
 *  Adds a clipping region to the global defs element.
 *  @param {DvtGraphClipPath}  cp  the DvtGraphClipPath object specifying the clipping region(s).
 *  @returns {boolean}    true if the clipping paths was successfully or already added, else false.
 */
DvtSvgShapeUtils.addClipPath = function(cp, context) {
  var id = cp.getId() ;
  if (! id) {
    return  false;    // essential to have an id to reference
  }

  var elemDefs = context.getDefs() ; 
  if (! elemDefs) {
    return false;
  }

  // Check if clipping path for this id is already defined.
  var defsChildren = elemDefs.childNodes ;
  var len          = defsChildren.length ;
  for (var i = 0; i < len; i++) {
    var el = defsChildren[i] ;
    if (el.id === id)
      return true;
  }
  
  var elemClip  = DvtSvgShapeUtils.createElement('clipPath', id) ;
  context.appendDefs(elemClip) ;
  
  var regions = cp.getRegions() ;
  for (var i = 0; i < regions.length; i++) {
     var region = regions[i] ;
     if (region) {
       var  elem = null ;
       if (region.type === DvtGraphClipPath.RECT) {
          elem = DvtSvgShapeUtils.createElement('rect') ;
          DvtSvgUtils.setAttrNullNS(elem, 'x',      region.x) ;
          DvtSvgUtils.setAttrNullNS(elem, 'y',      region.y) ;
          DvtSvgUtils.setAttrNullNS(elem, 'width',  region.w) ;
          DvtSvgUtils.setAttrNullNS(elem, 'height', region.h) ;
          if (region.rx)
            DvtSvgUtils.setAttrNullNS(elem, 'rx', region.rx) ;
          if (region.ry)
            DvtSvgUtils.setAttrNullNS(elem, 'ry', region.ry) ;
       }
       else if (region.type === DvtGraphClipPath.PATH) {
          elem = DvtSvgShapeUtils.createElement('path') ;
          DvtSvgUtils.setAttrNullNS(elem, 'd', region.d) ;
       }
       else if (region.type === DvtGraphClipPath.POLYGON) {
          elem = DvtSvgShapeUtils.createElement('polygon') ;
          DvtSvgUtils.setAttrNullNS(elem, 'points', region.points) ;
       }
       else if (region.type === DvtGraphClipPath.ELLIPSE) {
          elem = DvtSvgShapeUtils.createElement('ellipse') ;
          DvtSvgUtils.setAttrNullNS(elem, 'cx', region.cx) ;
          DvtSvgUtils.setAttrNullNS(elem, 'cy', region.cy) ;
          DvtSvgUtils.setAttrNullNS(elem, 'rx', region.rx) ;
          DvtSvgUtils.setAttrNullNS(elem, 'ry', region.ry) ;
       }
       else if (region.type === DvtGraphClipPath.CIRCLE) {
          elem = DvtSvgShapeUtils.createElement('circle') ;
          DvtSvgUtils.setAttrNullNS(elem, 'cx', region.cx) ;
          DvtSvgUtils.setAttrNullNS(elem, 'cy', region.cy) ;
          DvtSvgUtils.setAttrNullNS(elem, 'r', region.r) ;
       }

       if (elem)
         DvtSvgUtils.appendChildElem(elemClip, elem) ;
     }
  }

  return true ;
};


/*---------------------------------------------------------------------*/
/*   createElement()        Create an SVG DOM element                  */
/*---------------------------------------------------------------------*/
/**
  *  Creates an SVG DOM element.  
  * @param {String} name 
  * @param {String} id  Optional ID to be applied to the created DOM element.
  * @type DOM_Element
  * @base DvtSvgShapeUtils
  */
DvtSvgShapeUtils.createElement = function(name, id)
{
   var elem = document.createElementNS(DvtSvgUtils.SVG_NS, name) ;

   if (id) {
     DvtSvgUtils.setAttrNullNS(elem, 'id', id) ;
   }
     
   return elem ;
} ;



/*---------------------------------------------------------------------*/
/*   getUniqueId()              Returns a unique ID string             */
/*---------------------------------------------------------------------*/
/**
 *  Creates a unique ID string
 * @param {DvtContext} context The rendering context
 * @param {String} sPrefix  Optional string used as a prefix for the generated ID. If 
 *                          omitted, the ID generated will be prefixed with '$'.
 * @returns {String}        A unique ID string
 */
DvtSvgShapeUtils.getUniqueId = function(context, sPrefix)
{
  var uniqueId = (sPrefix? sPrefix : '$') + DvtSvgShapeUtils._uniqueSeed++ ;
  if (DvtAgent.isEnvironmentTest())
    return (context ? context.getStage().getId() + '_' : '') + uniqueId;
  else
    return uniqueId;
} ;

/**
 * Converts an array of x,y coordinate pairs into an SVG style string.
 * @param {array} arPoints the array of points
 * @returns {Array}  the string usable by SVG polygons and polylines
 */
DvtSvgShapeUtils.convertPointsArray = function(arPoints) {
  var len = arPoints.length ;   // convert to svg space separated list
  var s = '' ;

  for (var i = 0; i < len; i++) {
    if (i > 0) {
      s += ' ' ;
    }
    s += arPoints[i] ;
  }
  return s;
}





// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*   DvtSvgShape            Abstract base class for all shapes         */
/*---------------------------------------------------------------------*/
/**
 * A base class for shapes implemented via SVG.  Implements common DvtShape
 * drawing support for properties such as such as stroke and fill types and colors.
 * DvtSvgShape is intended to be subclassed.
 * @extends DvtSvgContainer
 * @class DvtSvgShape
 * @constructor
 * @param {string} id   An id for the object.
 * @param {string} type The SVG DOM element type - e.g. 'circle', 'rect', etc.
 */
var DvtSvgShape = function (id, type) {
  this._Init(id, type);
};

//  Allow shapes to become 'containers' themselves.  Note: this does not
//  provide a true parent/child relationship since this not available in SVG.
DvtObj.createSubclass(DvtSvgShape, DvtSvgContainer, "DvtSvgShape");




/*---------------------------------------------------------------------*/
/*  _Init()                                                            */
/*---------------------------------------------------------------------*/
/** @private */
DvtSvgShape.prototype._Init = function (id, type) {
  DvtSvgShape.superclass._Init.call(this, id, type);

  //  Base shape properties
  this._stroke = null;
  this._fill = null;
  this._origFill = null;
  this._origStroke = null;
  this._bHollow = false;

  // Since setFill() may never be called, will set a default no 'fill'
  DvtSvgUtils.setAttrNullNS(this._elem, 'fill', 'none');
};

/*---------------------------------------------------------------------*/
/*   get/setFill()                                                     */
/*---------------------------------------------------------------------*/
/**
 *  Returns the fill object (derivative of {@link DvtFill}) applied to this shape.
 * @type DvtFill
 */
DvtSvgShape.prototype.getFill = function () {
  return this._fill;
};

/**
 *  Sets the fill properties on this shape from the supplied fill object (a
 *  derivative of {@link DvtFill}).
 *  @param {DvtFill}  obj  A fill object. If null is specified, a transparent
 *  fill results.
 */
DvtSvgShape.prototype.setFill = function (obj) {
  
  this._manageDefinitions(this._fill, obj);

  if (!obj) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'fill', 'none');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'fill-opacity');
    this._fill = null;
    return;
  }
  else {
    if (this._fill === obj) {
      return;
    }
  }
  this._fill = obj;

  if (obj instanceof DvtGradientFill || obj instanceof DvtImageFill || obj instanceof DvtPatternFill)
    this._setSpecFill(obj);
  else { //  Basic fill
    var color = obj.getColor();
    if (color) {
      var alpha = obj.getAlpha();
      // Workaround for Safari where versions < 5.1 draw rgba values as black
      if (DvtAgent.isBrowserSafari() && color.indexOf("rgba") !==  - 1) {
        DvtSvgUtils.setAttrNullNS(this._elem, 'fill', DvtColorUtils.getRGB(color));
        // Use alpa in rgba value as a multiplier to the alpha set on the object as this is what svg does.
        if (alpha != null)
          DvtSvgUtils.setAttrNullNS(this._elem, 'fill-opacity', DvtColorUtils.getAlpha(color) * alpha);
        else 
          DvtSvgUtils.setAttrNullNS(this._elem, 'fill-opacity', DvtColorUtils.getAlpha(color));
      }
      else {
        DvtSvgUtils.setAttrNullNS(this._elem, 'fill', color);
        if (alpha != null)
          DvtSvgUtils.setAttrNullNS(this._elem, 'fill-opacity', alpha);
      }
    }
  }
};

DvtSvgShape.prototype._setSpecFill = function (obj, func) {
  var id;
  if (!obj.isLocked()) {
    id = obj.getId();
    if (!id) {
      if (obj instanceof DvtPatternFill) {
        id = DvtSvgShapeUtils.getUniqueId(this.getObj().getCtx(), "pat");// no id - create unique internal id
      }
      else {
        id = DvtSvgShapeUtils.getUniqueId(this.getObj().getCtx(), 'Gr');// no id - create unique internal id
      }
      obj.setId(id);
    }
  }
  else {
    id = obj.getId();
  }
  if (!obj._defPresent) {
    var elem = obj._defElem;
    if (!elem) {
      if (obj instanceof DvtGradientFill) 
        elem = DvtSvgGradientUtils.createElem(obj, id);
      else if (obj instanceof DvtImageFill) 
        elem = DvtSvgImageFillUtils.createElem(obj, id);
      else if (obj instanceof DvtPatternFill)
        elem = DvtSvgPatternFillUtils.createElem(obj, id);
    }
    obj._defElem = elem;
    this.getObj().getCtx().appendDefs(elem);
    obj._defPresent = true;
  }
  
  DvtSvgUtils.setAttrNullNS(this._elem, 'fill', 'url(#' + id + ')');
  DvtSvgUtils.setAttrNullNS(this._elem, 'fill-opacity', '1');
};

/*---------------------------------------------------------------------*/
/*   get/setStroke()                                                   */
/*---------------------------------------------------------------------*/
/**
 *  Returns the stroke object (derivative of {@link DvtStroke}) applied to this shape.
 * @type DvtStroke
 */
DvtSvgShape.prototype.getStroke = function () {
  return this._stroke;
};

/**
 *  Sets the stroke properties on this shape from the supplied stroke object.
 *  If the stroke object is null, any existing stroke is removed.
 *  @param {DvtStroke}  obj  A stroke object.
 */
DvtSvgShape.prototype.setStroke = function (obj) {

  this._manageDefinitions(this._stroke, obj);
  
  this._stroke = obj;

  if (!obj) {
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-opacity');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-width');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-dasharray');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-dashoffset');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-linejoin');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-linecap');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-miterlimit');
    return;
  }

  //  Stroke color/alpha
  // gradient
  if (obj instanceof DvtGradientStroke) {
    this._setSpecStroke(obj);
  }
  else {
    var color = obj.getColor();
    if (color) {
      var alpha = obj.getAlpha();
      // Workaround for Safari where versions < 5.1 draw rgba values as black
      if (DvtAgent.isBrowserSafari() && color.indexOf("rgba") !==  - 1) {
        DvtSvgUtils.setAttrNullNS(this._elem, 'stroke', DvtColorUtils.getRGB(color));
        // Use alpa in rgba value as a multiplier to the alpha set on the object as this is what svg does.
        if (alpha != null)
          DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-opacity', DvtColorUtils.getAlpha(color) * alpha);
        else 
          DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-opacity', DvtColorUtils.getAlpha(color));
      }
      else {
        DvtSvgUtils.setAttrNullNS(this._elem, 'stroke', color);
        if (alpha != null)
          DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-opacity', alpha);
      }
    }
  }

  //  Stroke width
  DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-width', obj.getWidth());
  
  if (obj.isFixedWidth())
    DvtSvgUtils.setAttrNullNS(this._elem, 'vector-effect', 'non-scaling-stroke');

  //  Stroke type/style
  var st = obj.getType();
  if (st !== DvtStroke.SOLID) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-dasharray', obj.getDash());
    if (obj.getDashOffset()) {
      DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-dashoffset', obj.getDashOffset());      
    }
  }
  else {
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-dasharray');
    DvtSvgUtils.removeAttrNullNS(this._elem, 'stroke-dashoffset');
  }

  //  Line-joining attribute
  attrib = obj.getLineJoin();
  if (attrib) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-linejoin', attrib);
  }

  //  Line-ending attribute
  attrib = obj.getLineEnd();
  if (attrib) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-linecap', attrib);
  }

  //  miter limit attribute
  attrib = obj.getMiterLimit();
  if (attrib) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-miterlimit', attrib);
  }
};

/**
 * Private helper function to create gradient, add it to def section of the SVG DOM,
 * and set the stroke to point to the gradient def
 * @private
 */
DvtSvgShape.prototype._setSpecStroke = function (obj, func) {
  var id;
  if (!obj.isLocked()) {
    id = obj.getId();
    if (!id) {
      id = DvtSvgShapeUtils.getUniqueId(this.getObj().getCtx(), 'Gr');// no id - create unique internal id
      obj.setId(id);
    }
  }
  else {
    id = obj.getId();
  }
  
  if (!obj._defPresent) {
      var elem = obj._defElem;
      if (!elem)
          elem = DvtSvgGradientUtils.createElem(obj, id);// create SVG DOM elem
      obj._defElem = elem;
      this.getObj().getCtx().appendDefs(elem);
      obj._defPresent = true;
  }


  DvtSvgUtils.setAttrNullNS(this._elem, 'stroke', 'url(#' + id + ')');
  var alpha = obj.getAlpha();
  if (alpha != null) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'stroke-opacity', alpha);
  }
};

/**  Changes the shape to an outline shape format.  Used for legends
 *  markers that represent a hidden state for the associated series risers.
 *  @param {String} fc Border color for hollow shape in format of #aarrggbb
 *  @param {number} strokeWidth Stroke width used for shapes that were transofrmed (optional)
 */
DvtSvgShape.prototype.setHollow = function (fc, strokeWidth) {
  if (!this._bHollow) {
    // Save original fill and stroke to restore 
    this._origFill = this._fill;
    this._origStroke = this._stroke;
    // Set hollow shape fill and stroke based on shape fill
    var hollowFill = DvtSolidFill.invisibleFill();
    var hollowStroke;
    if (fc) {
      hollowStroke = new DvtSolidStroke(DvtColorUtils.getRGB(fc), DvtColorUtils.getAlpha(fc), strokeWidth);
    }
    else {
      hollowStroke = new DvtSolidStroke(this._fill.getColor(), this._fill.getAlpha(), strokeWidth);
    }
    this.setFill(hollowFill);
    this.setStroke(hollowStroke);
    this._bHollow = true;
  }
  else {
    this.setFill(this._origFill);
    this.setStroke(this._origStroke);
    this._bHollow = false;
  }
};

/**  Returns whether a shape is hollow.
 *  @returns {boolean} True if the shape is hollow
 */
DvtSvgShape.prototype.isHollow = function () {
  return this._bHollow;
}

/*
 * Manage the gradient/filter definitions for svg by keeping a reference count and removing unreferenced defs
 */
DvtSvgShape.prototype._manageDefinitions = function(oldObj, newObj) {
  // If a new obj is specified, adjust reference counts and remove def if 0 references
  if (oldObj != newObj) {
    // Decrease count on existing obj
    if (oldObj) {
        oldObj._referenceCount--;
        if (oldObj._referenceCount == 0) {
            if (oldObj._defElem) {
                this.getObj().getCtx().removeDefs(oldObj._defElem);
                oldObj._defPresent = false;
            }
        }

    }
    if (newObj) {
        if (!newObj._referenceCount)
            newObj._referenceCount = 0;
        newObj._referenceCount++;
    }
  }
}

//BUG FIX 13842194:
/**
 * @override
 */
DvtSvgShape.prototype.getDimensionsWithStroke = function() {
  //get the dims for this shape by itself
  var dims = this.GetElemDimensionsWithStroke();
  //get the dims for any children of this container
  var containerDims = DvtSvgShape.superclass.getDimensionsWithStroke.call(this);
  //create union of shape and container dims
  if (dims && containerDims) {
    dims = dims.getUnion(containerDims);
  }
  else if (containerDims) {
    dims = containerDims;
  }
  
  return dims;
};

//BUG FIX 13842194:
DvtSvgShape.prototype.GetDimensionsWithStroke = function(targetCoordinateSpace) {
  //get the dims for this shape by itself
  var dims = this.GetElemDimensionsWithStroke();
  if (!targetCoordinateSpace || targetCoordinateSpace === this.getObj())
    return dims;
  else { // Calculate the bounds relative to the target space
    return this.getObj().ConvertCoordSpaceRect(dims, targetCoordinateSpace);
  }
};

//BUG FIX 13842194:
DvtSvgShape.prototype.GetElemDimensionsWithStroke = function() {
  //get the dims for this shape by itself
  var dims = DvtSvgShape.superclass.GetElemDimensionsWithStroke.call(this);
  //assume that stroke touches every edge of bounding box, so push out
  //every edge by half the stroke width
  var stroke = this.getStroke();
  if (dims && stroke) {
    var sw = stroke.getWidth();
    if (sw) {
      var halfSw = .5 * sw;
      dims.x -= halfSw;
      dims.y -= halfSw;
      dims.w += sw;
      dims.h += sw;
    }
  }
  return dims;
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*    DvtSvgArc                 Svg implementation of arc              */
/*---------------------------------------------------------------------*/
/**
  *  Creates an arc (a portion of an ellipse or circle) implemented by SVG.
  *  @extends DvtSvgShape
  *  @class  DvtSvgArc  Creates an arc (a portion of an ellipse or circle)
  *  implemented by SVG.  Do not create directly, use DvtArc.
  *  <p>
  *  Example:<br><br><code>
  *  //  Create an arc from an ellipse centered at (50,50) with radii 100 and<br>
  *  // 200, and starting at angle 40, for an extent of 75.<br><br>
  *  var  arc = new DvtArc(context,50,50,100,200,40, 75);<br><br>
  *  //  Create an arc from a circle centered at (50,50) with radii 100<br>
  *  //  starting at angle 40, for an extent of 75.<br><br>
  *  var  arc = new DvtArc(context,50,50,100,40,75);<br>
  *  </code>
  *  @constructor  
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} rx  The horizontal radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse. (use the same value as
  *                      the horizontal radius if a circular arc.)
  *  @param {number} sa  The starting angle in degrees (following the normal anti-clockwise is positive convention).
  *  @param {number} ae  The angle extent in degrees (following the normal anti-clockwise is positive convention).
  *  @param {String} clos  An optional closure type for the arc. Closure types are {@link DvtArc#OPEN} (the default),
  *                        {@link DvtArc#CHORD} and {@link DvtArc#PIE}.
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSvgArc = function(cx, cy, rx, ry, sa, ae, clos, id)
{
   this._Init(cx, cy, rx, ry, sa, ae, clos, id) ;
};

DvtObj.createSubclass(DvtSvgArc, DvtSvgShape, "DvtSvgArc") ;



/*---------------------------------------------------------------------*/
/*  _AddClosure()                                                      */
/*---------------------------------------------------------------------*/
/** @private */
DvtSvgArc.prototype._addClosure = function(p)
{
  if (this._ct === DvtArc.CHORD) {
    p += ' z' ;
  }
  else if (this._ct === DvtArc.PIE) {
    p += ' L ' + this._cx + ',' + this._cy + ' z' ;
  }
  else if (this._ct === DvtArc.OPEN) {
    this.setFill(null) ;
  }

  return p ;
} ;



/*---------------------------------------------------------------------*/
/*  _createArc()                                                       */
/*---------------------------------------------------------------------*/
/**
  *   @private
  */
DvtSvgArc.prototype._createArc = function()
{
   if (this._bInInit) {       // don't need to do this until end of Init()
     return ;
   }

   var sa = (this._sa * DvtMath.RADS_PER_DEGREE);
   var ae = (this._ae * DvtMath.RADS_PER_DEGREE);

   var x1 = this._cx + (this._rx * Math.cos(sa)) ;        // get arc
   var y1 = this._cy - (this._ry * Math.sin(sa)) ;        // end points
   var x2 = this._cx + (this._rx * Math.cos(sa + ae)) ;
   var y2 = this._cy - (this._ry * Math.sin(sa + ae)) ;

   var nLargeArc  =  (Math.abs(this._ae) > 180)? '1' : '0' ;
   var nSweepFlag =  (this._ae > 0)? '0' : '1' ;     // 0 == svg +ve angle

   var path = "M " +  x1 + " " + y1 + " A " + this._rx + "," + this._ry + " " + "0" + " " +
              nLargeArc + "," + nSweepFlag + " " + x2 + "," + y2 ;   
   path = this._addClosure(path) ;

   DvtSvgUtils.setAttrNullNS(this._elem, 'd', path) ;
   if (this._stroke !== null) {
     this.setStroke(this._stroke) ;
   }
} ;






/*---------------------------------------------------------------------*/
/*   getAngleExtent()                                                  */
/*---------------------------------------------------------------------*/
/**
  *  Returns the angle subtended by the arc.
  *  @returns {number}  The angle subtended by the arc (following the normal anti-clockwise
  *  is positive convention).
  */
DvtSvgArc.prototype.getAngleExtent = function()
{
   return this._ae ;
} ;
/**
  *  Returns the angle subtended by the arc.
  *  @returns {number}  The angle subtended by the arc.
  *  is positive convention).
  */
DvtSvgArc.prototype.setAngleExtent = function(ae)
{
   ae = ((ae === null || isNaN(ae)) ? 0 : ae);
   if (this._ae !== ae) {

     //  From https://developer.mozilla.org/en/SVG/Tutorial/Paths
     //  "Complete circles and ellipses are actually the one object paths have trouble drawing.
     //  Because the start and end points for any path going around a circle are the same, there
     //  are an infinite number of circles that could be chosen, and the actual path is undefined.
     //  It's possible to approximate them by making the start and end points of your path slightly askew"

     if (ae === 360) {               // bug 12723079
       ae = 359.99 ;                 // cannnot use any precision higher than this!
     }

     this._ae = ae;
     this._createArc() ;
   }
} ;


/*---------------------------------------------------------------------*/
/*   getAngleStart()                                                   */
/*---------------------------------------------------------------------*/
/**
  *  Returns the start angle for an arc.
  *  @returns {number}  The starting angle (following the normal anti-clockwise
  *  is positive convention).
  */
DvtSvgArc.prototype.getAngleStart = function()
{
   return this._sa ;
} ;

/**
  *  Sets the start angle of the arc.
  *  @param {number}  The starting angle (following the normal anti-clockwise
  *  is positive convention).
  */
DvtSvgArc.prototype.setAngleStart = function(sa)
{
   sa = ((sa === null || isNaN(sa)) ? 0 : sa);
   if (this._sa !== sa) {
     this._sa = sa;
     this._createArc() ;
   }
} ;



/*---------------------------------------------------------------------*/
/*   get/setClosure()                                                  */
/*---------------------------------------------------------------------*/
/**
  *    Returns the closure type of the arc.
  *    @type String
  *    @returns The closure type,  such as {@link DvtArc#OPEN}
  */
DvtSvgArc.prototype.getClosure = function()
{
   return this._ct ;
} ;

/**
  *  Sets the closure type of the arc.
  *  @param {String} ct   The closure type,  such as {@link DvtArc#OPEN}
  */
DvtSvgArc.prototype.setClosure = function(ct)
{
   if (ct !== this._ct) {
     this._ct  = ct ;
     this._createArc() ;
   }

} ;



/*---------------------------------------------------------------------*/
/*  _Init()                                                            */
/*---------------------------------------------------------------------*/
/** @private */

DvtSvgArc.prototype._Init = function(cx, cy, rx, ry, sa, ae, clos, id)
{
   DvtSvgArc.superclass._Init.call(this, id, 'path') ;

   this._sa = 0 ;
   this._ae = 0 ;

   ry = ((ry === null || isNaN(ry)) ? rx : ry);

   this._bInInit = true ;         // performance - avoid multiple createArc()'s
   this.setCx(cx);
   this.setCy(cy);
   this.setRx(rx);
   this.setRy(ry);
   this.setAngleStart(sa);
   this.setAngleExtent(ae);
   this.setClosure(clos ? clos : DvtArc.OPEN);
   this._bInInit = false ;        // finally allow createArc to work.

   this._createArc() ;

} ;


/*---------------------------------------------------------------------*/
/*   setArc()         Convenience method                               */
/*---------------------------------------------------------------------*/
/**
  *  Defines the position and extent of the arc.
  *  @param {number} sa  The starting angle in degrees (following the normal
  *  anti-clockwise is positive convention).
  *  @param {number} ae  The angle extent in degrees (following the normal
  *  anti-clockwise is positive convention).
  */
DvtSvgArc.prototype.setArc = function(sa, ae)
{
   this.setAngleStart(sa) ;
   this.setAngleExtentStart(ae) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setCx()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Returns the x coordinate of the center.
  *  @type number
  */
DvtSvgArc.prototype.getCx = function()
{
   return  this._cx ;
} ;
/**
  *  Sets the x coordinate of the center.
  *  @param {number} cx  The center x position.
  */
DvtSvgArc.prototype.setCx = function(cx)
{
   if (cx !== this._cx) {
     this._cx  = cx ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'cx', cx) ;
   }
} ;


/*---------------------------------------------------------------------*/
/*   get/setCy()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Returns the y coordinate of the center.
  *  @type number
  */
DvtSvgArc.prototype.getCy = function()
{
   return  this._cy ;
} ;

/**
  *  Sets the y coordinate of the center.
  *  @param {number} cy  The center y position.
  *
  */
DvtSvgArc.prototype.setCy = function(cy)
{
   if (cy !== this._cy) {
     this._cy  = cy ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'cy', cy) ;
   }
} ;


/*---------------------------------------------------------------------*/
/*   get/setRx()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Returns the horizontal radius of the ellipse.
  *  @type number
  */
DvtSvgArc.prototype.getRx = function()
{
   return this._rx ;
} ;

/**
  *  Sets the horizontal radii of the ellipse.
  *  @param {number} rx  The horizontal radius of the ellipse.
  */
DvtSvgArc.prototype.setRx = function(rx)
{
   if (rx !== this._rx) {
     this._rx  = rx ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'rx', this._rx) ;
   }
} ;


/*---------------------------------------------------------------------*/
/*   get/setRy()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Returns the vertical radius of the ellipse.
  *  @type number
  */
DvtSvgArc.prototype.getRy = function()
{
   return this._ry ;
} ;

/**
  *  Sets the vertical radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  */
DvtSvgArc.prototype.setRy = function(ry)
{
   if (ry !== this._ry) {
     this._ry  = ry ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'ry', this._ry) ;
   }
} ;


// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*-------------------------------------------------------------------------*/
/*   DvtSvgCircle         SVG Implementation of base circular shape        */
/*-------------------------------------------------------------------------*/
/**
  *  Creates a circular displayable shape - SVG implementation of DvtCircle.
  *  @extends DvtSvgShape
  *  @class DvtSvgCircle is an SVG implementation of DvtCircle and displays
  *  a circle.  Note:  this class should not be used directly, use DvtCircle.
  *  <p>
  *  <b>Example:</b><br><br> <code>
  *  var circle = new DvtCircle(context,10, 10, 100, 'myCircle') ;<br>
  *  circle.setStroke(new DvtStroke("red", 5)) ;<br>
  *</code>
  *
  *   @constructor  
  *   @param {number} cx  The center x position.
  *   @param {number} cy  The center y position.
  *   @param {number} r   The radius of the circle.
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var   DvtSvgCircle = function(cx, cy, r, id)
{
   this._Init(cx, cy, r, id) ;
};

DvtObj.createSubclass(DvtSvgCircle, DvtSvgShape, "DvtSvgCircle") ;



/*-------------------------------------------------------------------------*/
/*  Init()                                                                 */
/*-------------------------------------------------------------------------*/
/** @private */
DvtSvgCircle.prototype._Init = function(cx, cy, r, id, type)
{
   DvtSvgCircle.superclass._Init.call(this, id, (type ? type : 'circle')) ;

   this.setCx(cx);
   this.setCy(cy);
   this.setRadius(r);
} ;



/*-------------------------------------------------------------------------*/
/*   get/setCx()                                                           */
/*-------------------------------------------------------------------------*/

DvtSvgCircle.prototype.getCx = function()
{
   return  this._cx ;
} ;
/**
  *  Sets the x coordinate of the center.
  *  @param {number} cx  The center x position.
  */

DvtSvgCircle.prototype.setCx = function(cx)
{
   if (cx !== this._cx) {
     this._cx  = cx ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'cx', cx) ;
   }
} ;


/*-------------------------------------------------------------------------*/
/*   get/setCy()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the y coordinate of the center.
  *  @type number
  */
DvtSvgCircle.prototype.getCy = function()
{
   return  this._cy ;
} ;

/**
  *  Sets the y coordinate of the center.
  *  @param {number} cy  The center y position.
  *
  */
DvtSvgCircle.prototype.setCy = function(cy)
{
   if (cy !== this._cy) {
     this._cy  = cy ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'cy', cy) ;
   }
} ;

/*-------------------------------------------------------------------------*/
/*   setRadius()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Gets the radius  of the circle.
  *  @type {Number}  The radius of the circle.
  */
DvtSvgCircle.prototype.getRadius = function()
{
   return  this._r ;
} ;

/**
  *  Sets the radius  of the circle.
  *  @param {number} r   The radius of the circle.
  */
DvtSvgCircle.prototype.setRadius = function(r)
{
  if(r !== this._r) {
    this._r  = r ;
    DvtSvgUtils.setAttrNullNS(this._elem, 'r', r) ;
  }
} ;

// Copyright (c) 2011, 2023, Oracle and/or its affiliates.
/*-------------------------------------------------------------------------*/
/*    DvtSvgImage           Svg implementation for base shape DvtImage        */
/*-------------------------------------------------------------------------*/
/**
  *   Svg implementation for DvtImage.
  *   @constructor  
  *   Maybe specified as individual values or using a DvtImage object.
  *
  *   e.g. Image = new DvtImage(context,'pic'png', 10, 10, 50, 100);  or
  *
  *        Image = new DvtImage(context, myImage);   where myImage = new DvtImage(context,'pic.png', 10, 10, 50, 100);
  *
  */
var  DvtSvgImage = function(src, x, y, w, h, id)
{
  this._Init(src, x, y, w, h, id) ;
}

DvtObj.createSubclass(DvtSvgImage, DvtSvgShape, "DvtSvgImage");



DvtSvgImage.XLINK_NS = "http://www.w3.org/1999/xlink";

/**
 * Helper method called by the constructor for initializing this object
 * @param {string} src The url for the image
 * @param {number} x The top left x-coordinate of the image
 * @param {number} y The top left y-coordinate of the image
 * @param {number} w The image width
 * @param {number} h The image height
 * @param {string} id The identifier for the image
 * @private
 */
DvtSvgImage.prototype._Init = function(src, x, y, w, h, id)
{
  DvtSvgImage.superclass._Init.call(this, id, 'image') ;
  // IE doesn't allow interactivity unless there's a fill
  if (DvtAgent.isPlatformIE()) {
    DvtSvgUtils.setAttrNullNS(this._elem, 'fill', '#FFFFFF');
    DvtSvgUtils.setAttrNullNS(this._elem, 'fill-opacity', '0');
  }
  this.setImage(src, x, y, w, h);
} ;



/*-------------------------------------------------------------------------*/
/*   get/setHeight()                                                       */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the height of the rectangle.
  *  @type number
  */
DvtSvgImage.prototype.getHeight = function()
{
   return  this._h ;
} ;

/**
  *  Sets the height of the image.
  *  @param {number} h  The height of the image.
  *  @returns nothing
  */
DvtSvgImage.prototype.setHeight= function(h)
{
   if (h !== this._h) {
     this._h  = h ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'height', this._h) ;
   }
} ;



/*-------------------------------------------------------------------------*/
/*   get/setPos(x,y)                                                       */
/*-------------------------------------------------------------------------*/

DvtSvgImage.prototype.getPos = function()
{
   return new DvtPoint(this._x, this._y) ;
};

DvtSvgImage.prototype.setPos= function(x,y)
{
   this.setX(x) ;
   this.setY(y) ;
};



/*-------------------------------------------------------------------------*/
/*   get/setX()                                                            */
/*-------------------------------------------------------------------------*/

DvtSvgImage.prototype.getX = function()
{
   return this._x ;
} ;

DvtSvgImage.prototype.setX = function(x)
{
   if (x !== this._x) {
     this._x  = x ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'x', this._x) ;
   }
} ;

/*-------------------------------------------------------------------------*/
/*   get/setY()                                                            */
/*-------------------------------------------------------------------------*/

DvtSvgImage.prototype.getY = function()
{
   return this._y ;
} ;
DvtSvgImage.prototype.setY = function(y)
{
   if (y !== this._y) {
     this._y  = y ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'y', this._y) ;
   }
} ;


/*-------------------------------------------------------------------------*/
/*   get/setWidth()                                                        */
/*-------------------------------------------------------------------------*/

DvtSvgImage.prototype.getWidth = function()
{
   return this._w ;
} ;

/**
  *  Sets the width of the image.
  *  @param {number} w  The width of the image.
  *  @returns nothing
  */
DvtSvgImage.prototype.setWidth = function(w)
{
   if (w !== this._w) {
     this._w  = w ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'width', this._w) ;
   }
} ;

/*-------------------------------------------------------------------------*/
/*   get/setSrc()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the src of the image.
  *  @returns (String) the src of the image.
  */
DvtSvgImage.prototype.getSrc = function()
{
  return this._src;
} ;

/**
  *  Sets the src of the image.
  *  @param {number} src  The src of the image.
  *  @returns nothing
  */
DvtSvgImage.prototype.setSrc = function(src)
{
   if (src !== this._src) {
     this._src  = src ;

     //TODO: 
     // DvtSvgUtils.setAttrNS(this._elem, "xlink", 'href', this._src) ;
     DvtSvgUtils.setAttrNS(this._elem, DvtSvgImage.XLINK_NS, 'xlink:href', this._src) ;
   }
} ;


/*-------------------------------------------------------------------------*/
/*   setImage()                                                            */
/*-------------------------------------------------------------------------*/
/**
  *     Sets the position and size and src of the image
  *     Maybe specified as individual values or using a DvtImage object.
  *
  *   e.g. Image = factory.newImage('pic'png', 10, 10, 50, 100);  or
  *
  *        Image = factory.newImage(myImage);   where myImage = new DvtImage('pic.png', 10, 10, 50, 100);
  */
DvtSvgImage.prototype.setImage = function(src,x,y,w,h)
{
   if (x instanceof DvtImage) {
     this.setSrc(src.src);
     this.setPos(src.x, src.y) ;
     this.setWidth(src.w) ;
     this.setHeight(src.h) ;
   }
   else {
     this.setSrc(src);
     this.setPos(x,y) ;
     this.setWidth(w) ;
     this.setHeight(h) ;
   }

   //TODO: set preserveAspectRatio="none" for now
   DvtSvgUtils.setAttrNullNS(this._elem, 'preserveAspectRatio', 'none') ;
} ;


/**
 * @override
 */
DvtSvgImage.prototype.getDimensions = function() {
  var bbox = this.getElem().getBBox();

  if (bbox.width && bbox.height) {
    return new DvtRectangle(bbox.x, bbox.y, bbox.width, bbox.height);
  }
  else {
    return new DvtRectangle(bbox.x, bbox.y, this.getWidth(), this.getHeight());
  }

};


/**
  *  Loads the image and sets the image size if it was loaded
  *  Returns the dimension of the image if it was loaded
  */
DvtSvgImage.prototype.loadImage = function() {
  if (this._src) {
    var imageSize = DvtSvgImageLoader.loadImage(this._src);
    if (imageSize) {
      this.setWidth(imageSize.width);
      this.setHeight(imageSize.height);

      //BUG 17601740 - FIREFOX: NODE CONTENT COLLAPSED ON INITIAL RENDERING 
//      return this.getDimensions();
      return new DvtRectangle(0, 0, this.getWidth(), this.getHeight());
    }
  }
  return null;
}

// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*   DvtSvgLine          SVG Implementation of DvtLine                 */
/*---------------------------------------------------------------------*/
/**
  *   Creates an SVG implementation of a line segment drawn from (x1, y1) to (x2, y2).
  *   An object of this class must not created directly, use {@link DvtLine}.
  *   @extends DvtSvgShape
  *   @class DvtSvgLine
  *   @constructor  
  *   @param {number} x1  An x end-position of the line.
  *   @param {number} y1  The associated y end-point (for x1).
  *   @param {number} x2  The other end-point's x coordinate.
  *   @param {number} y2  The y coordinate associated with x2.
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var DvtSvgLine = function(x1, y1, x2, y2, id)
{
   this._Init(x1, y1, x2, y2, id) ;
};

DvtObj.createSubclass(DvtSvgLine, DvtSvgShape, "DvtSvgLine") ;


/*---------------------------------------------------------------------*/
/*   _Init()                                                           */
/*---------------------------------------------------------------------*/
/**   @private  */
DvtSvgLine.prototype._Init = function(x1, y1, x2, y2, id)
{
   DvtSvgLine.superclass._Init.call(this, id, 'line') ;

   DvtSvgUtils.setAttrNullNS(this._elem, 'fill', 'none') ;
   this.setX1(x1);
   this.setY1(y1);
   this.setX2(x2);
   this.setY2(y2);
   this._bHollow = false;
} ;

/*---------------------------------------------------------------------*/
/*   get/setX1()                                                       */
/*---------------------------------------------------------------------*/

DvtSvgLine.prototype.getX1 = function()
{
   return this._x1 ;
} ;

DvtSvgLine.prototype.setX1 = function(x1)
{
   if (x1 !== this._x1) {
     this._x1  = x1 ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'x1', this._x1) ;
   }
} ;

/*---------------------------------------------------------------------*/
/*   get/setY1()                                                       */
/*---------------------------------------------------------------------*/

DvtSvgLine.prototype.getY1 = function()
{
   return this._y1 ;
} ;

DvtSvgLine.prototype.setY1 = function(y1)
{
   if (y1 !== this._y1) {
     this._y1  = y1 ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'y1', this._y1) ;
   }
} ;

/*---------------------------------------------------------------------*/
/*   get/setX2()                                                       */
/*---------------------------------------------------------------------*/

DvtSvgLine.prototype.getX2 = function()
{
   return this._x2 ;
} ;

DvtSvgLine.prototype.setX2 = function(x2)
{
   if (x2 !== this._x2) {
     this._x2  = x2 ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'x2', this._x2) ;
   }
} ;

/*---------------------------------------------------------------------*/
/*   get/setY2()                                                       */
/*---------------------------------------------------------------------*/

DvtSvgLine.prototype.getY2 = function()
{
   return this._y2 ;
} ;

DvtSvgLine.prototype.setY2 = function(y2)
{
   if (y2 !== this._y2) {
     this._y2  = y2 ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'y2', this._y2) ;
   }
} ;

/**  Changes the shape to an outline shape format.  Used for legend
  *  markers that represent a hidden state for the associated series risers.
  *                            reinstates the pevious state.
  *  @override
  */
DvtSvgLine.prototype.setHollow = function()
{
    var  parentElem = this._elem.parentNode ;

    if (!this._bHollow) {
        this._origElem   = this._elem;
        var hollowMarker; 
        var width  = this.getX2() - this.getX1() ;   // Legend lines are always horizontal, so take width as height
        var height = width ;
        var startY = this.getY1() - width/2 ;
        var stroke = this.getStroke();
        
        hollowMarker = DvtSvgShapeUtils.createElement('rect');
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'x', this.getX1()) ;
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'y', startY) ;
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'width', this.getX2() - this.getX1()) ;
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'height', height) ;
        var color = stroke.getColor();
        if (color) {
          var alpha = stroke.getAlpha();
          // Workaround for Safari where versions < 5.1 draw rgba values as black
          if (DvtAgent.isBrowserSafari() && color.indexOf("rgba") !==  - 1) {
            DvtSvgUtils.setAttrNullNS(hollowMarker, 'stroke', DvtColorUtils.getRGB(color));
            // Use alpa in rgba value as a multiplier to the alpha set on the object as this is what svg does.
            if (alpha != null)
              DvtSvgUtils.setAttrNullNS(hollowMarker, 'stroke-opacity', DvtColorUtils.getAlpha(color) * alpha);
            else 
              DvtSvgUtils.setAttrNullNS(hollowMarker, 'stroke-opacity', DvtColorUtils.getAlpha(color));
          }
          else {
            DvtSvgUtils.setAttrNullNS(hollowMarker, 'stroke', color);
            if (alpha != null)
              DvtSvgUtils.setAttrNullNS(hollowMarker, 'stroke-opacity', alpha);
          }
        }
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'fill', '#ffffff') ;
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'fill-opacity', '0.001') ;    // need this or hit detection fails on center
        DvtSvgUtils.setAttrNullNS(hollowMarker, 'shape-rendering', 'crispEdges') ;
        hollowMarker._obj = this;       // replace the elem's _obj backpointer 
        
        parentElem.replaceChild(hollowMarker, this._elem) ;
        this._elem = hollowMarker ;
        DvtSvgUtils.setAttrNullNS(this._elem, 'opacity', this._alpha);
        this._bHollow = true;
    }
    else if (this._origElem) {
        parentElem.replaceChild(this._origElem, this._elem) ;
        DvtSvgUtils.setAttrNullNS(this._origElem, 'opacity', this._alpha);
        this._elem = this._origElem ;
        this._origElem   = null ;
        this._bHollow = false;
    }
} ;  

/**  Returns whether a shape is hollow.
  *  @returns {boolean} True if the shape is hollow
  *  @override
  */
DvtSvgShape.prototype.isHollow = function() {
    return this._bHollow;
}

// TODO JSDoc
// Must be connected for this to work
DvtSvgLine.prototype.getDimensions = function(targetCoordinateSpace) {
  var bounds = DvtSvgLine.superclass.getDimensions.call(this, targetCoordinateSpace);
  // BUG #12806130: Vertical/horizontal lines in svg are ignored when group containers wrap them
  if (this._childGroupElem && this._elem) {
      var groupBox = this._childGroupElem.getBBox();
      // Empty bounding box is an indication of only vertical/horizontal lines present in this group
      // In this case, use the original line itself to get the bounds as an approximation
      if (groupBox.x == 0 && groupBox.y == 0 && groupBox.width == 0 && groupBox.height == 0) {
         var lineBounds = this._elem.getBBox();
         bounds = new DvtRectangle(lineBounds.x, lineBounds.y, lineBounds.width, lineBounds.height);
      }
  }
  return bounds;
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*--------------------------------------------------------------------*/
/*   DvtSvgMarker         SVG implementation of a DvtMarker           */
/*--------------------------------------------------------------------*/
/**
  *   An SVG implementation of DvtMarker
  *   @class An SVG implementation of DvtMarker. Do not create directly, use DvtMarker.
  *   @extends DvtSvgShape
  *   @constructor    Returns a DvtSvgMarker instance.
  *   @param {number} type  The marker type (such as {@link DvtMarker#CIRCLE}).
  *   @type  DvtSvgMarker
  */
var  DvtSvgMarker = function(type, id, etype)
{
  this._Init(type, id, etype) ; 
}  ;

DvtObj.createSubclass(DvtSvgMarker, DvtSvgShape, "DvtSvgMarker") ;

// The reference coords and sizes that the shapes will be initialized to.
DvtSvgMarker._REFERENCE_X = 0;
DvtSvgMarker._REFERENCE_Y = 0;
DvtSvgMarker._REFERENCE_W = 10;
DvtSvgMarker._REFERENCE_H = 10;

DvtSvgMarker.MARKER_CIRCLE_ELEM_NAME = "circle";
DvtSvgMarker.MARKER_ELLIPSE_ELEM_NAME = "ellipse";
DvtSvgMarker.MARKER_LINE_ELEM_NAME = "line";
DvtSvgMarker.MARKER_PATH_ELEM_NAME = "path";
DvtSvgMarker.MARKER_POLYGON_ELEM_NAME = "polygon";
DvtSvgMarker.MARKER_POLYLINE_ELEM_NAME = "polyline";
DvtSvgMarker.MARKER_RECT_ELEM_NAME = "rect";


/**
 * Initializes the svg element type based on the marker type
 * @param {string} type The marker type
 * @param {id} id The identifier for this marker
 * @param {string} etype The svg element type to use for this marker
 * @private
 */ 
DvtSvgMarker.prototype._Init = function(type, id, etype)
{
   var elemType;
   if (etype) {
     elemType = etype;
   }
   else {
     elemType = (type === DvtMarker.CIRCLE? 'ellipse' :
                (type === DvtMarker.SQUARE? 'rect' :
                (type === DvtMarker.ROUNDED_RECTANGLE? 'rect' :
                (type === DvtMarker.TRIANGLE_UP? 'polygon' :
                (type === DvtMarker.TRIANGLE_DOWN? 'polygon' :
                (type === DvtMarker.DIAMOND? 'polygon' :
                (type === DvtMarker.PLUS? 'polygon' :
                (type === DvtMarker.HUMAN? 'path' :
                (type === DvtMarker.IMAGE? 'image' : 'rect'))))))))) ;
   }         
   DvtSvgMarker.superclass._Init.call(this, id, elemType);
   
   // Store the type
   this._type = type;
   
   //Store reference to underlay
   this._underlay = null;
   
   //default scale of the marker used to force it to the reference size
   this._defaultScale = 1;
};

/**
 * Sets the position and size of the marker.
 * @param {number} x The top left x-coordinate of the marker's bounding rectangle.
 * @param {number} y The top left y-coordinate of the marker's bounding rectangle.
 * @param {number} w The width of the marker's bounding rectangle.
 * @param {number} h The height of the marker's bounding rectangle.
 * @param {DvtMarkerDef} markerDef
 */
DvtSvgMarker.prototype.setBounds = function(x, y, w, h, markerDef) {   
   // Initialize the shape to the reference coords
   if(!this._shapeInitialized)
     this._initShape(this._type, markerDef, x, y, w, h);  
}

/**
 * Initializes the shape to the specified coordinates.
 * @param {string} type The marker type
 * @param {DvtMarkerDef} markerDef The marker definition used for custom markers generated on the server
 * @param {number} x The top left x-coordinate of the marker's bounding rectangle.
 * @param {number} y The top left y-coordinate of the marker's bounding rectangle.
 * @param {number} w The width of the marker's bounding rectangle.
 * @param {number} h The height of the marker's bounding rectangle.
 * @private
 */
DvtSvgMarker.prototype._initShape = function (type, markerDef, x, y, w, h) {
  // Only need to do this once
  this._shapeInitialized = true;

  // Save info for underlay positioning
  this._x = x;
  this._y = y;
  this._w = w;
  this._h = h;

  var multiPathRoot;
  if (type === DvtMarker.CUSTOM || type === DvtMarker.HUMAN) {
    // Calculate the scale factor to get to the right size
    var dim = DvtDisplayableUtils._getDimForced(this.getObj().getCtx(),
                                                markerDef);
    var maxDim = Math.max(dim.w, dim.h);

    var sx = 1;
    var sy = 1;

    // Calculate the transform to get to the right position
    if (type === DvtMarker.CUSTOM) {
      sx = w/(this.getObj().getMaintainAspect() ? maxDim : dim.w);
      sy = h/(this.getObj().getMaintainAspect() ? maxDim : dim.h);
      var dx = x + (-dim.x * sx) + (w - (dim.w * sx))/2;
      var dy = y + (-dim.y * sy) + (h - (dim.h * sy))/2;
      multiPathRoot = this._setCustomMarker(markerDef, dx, dy, sx, sy);
    }
    else if (type === DvtMarker.HUMAN) {
      sx = w/maxDim;
      sy = h/maxDim;
      var dx = x + (-dim.x * sx) + (w - (dim.w * sx))/2;
      var dy = y + (-dim.y * sy) + (h - (dim.h * sy))/2;
      this._setCmds(DvtPathUtils.transformPath(this.getObj().getSkin() == DvtCSSStyle.SKIN_ALTA ? DvtMarkerDef.HUMAN2_CMDS :
                                                DvtMarkerDef.HUMAN_CMDS, dx, dy, sx, sy));
    }
    var scale = (dim.h === maxDim) ? (h/maxDim) : (w/maxDim);
    //save the default scale used to force the marker to the reference size
    //because we may need it later for inversely scaling the selection stroke
    this._defaultScale = scale;    
  }
  else if (type === DvtMarker.IMAGE) {
    var src = this.getObj().GetMarkerImage(DvtMarker.IMAGE_SOURCE);
    this._setX(x);
    this._setY(y);
    this._setWidth(w);
    this._setHeight(h);
    this.setSource(src);
    DvtSvgUtils.setAttrNullNS(this._elem, 'preserveAspectRatio', 'none') ;
    // IE doesn't allow interactivity unless there's a fill
    if (DvtAgent.isPlatformIE()) {
      DvtSvgUtils.setAttrNullNS(this._elem, 'fill', '#FFFFFF');
      DvtSvgUtils.setAttrNullNS(this._elem, 'fill-opacity', '0');
    }
  }
  else if (type === DvtMarker.SQUARE) {
    this._setX(x);
    this._setY(y);
    this._setWidth(w);
    this._setHeight(h);
  }
  else if (type === DvtMarker.ROUNDED_RECTANGLE) {
    this._setX(x);
    this._setY(y);
    this._setWidth(w);
    this._setHeight(h);
    var rx = 6;
    var ry = 6;
    if (w/4 < rx || h/4 < ry) {
      rx = Math.min(w, h)/4;
      ry = rx;
    }
    this._setRX(rx);
    this._setRY(ry);
  }
  else if (type === DvtMarker.CIRCLE) {
    this._setCx(x + w/2);
    this._setCy(y + h/2);
    this._setRX(w/2);
    this._setRY(h/2);
  }
  else {
    var ar = [];
    var halfWidth = w / 2;
    var halfHeight = h / 2;
   
    if (type === DvtMarker.TRIANGLE_UP) {
      ar.push(x);
      ar.push(y + h);
      ar.push(x + w);
      ar.push(y + h);
      ar.push(x + halfWidth);
      ar.push(y);
      this._setPolygon(ar);
    }
    else if (type === DvtMarker.TRIANGLE_DOWN) {
      ar.push(x);
      ar.push(y);
      ar.push(x + w);
      ar.push(y);
      ar.push(x + halfWidth);
      ar.push(y + h);
      this._setPolygon(ar);
    }
    else if (type === DvtMarker.DIAMOND) {
      ar.push(x + halfWidth);
      ar.push(y);
      ar.push(x + w);
      ar.push(y + halfHeight);
      ar.push(x + halfWidth);
      ar.push(y + h);
      ar.push(x);
      ar.push(y + halfHeight);
      this._setPolygon(ar);
    }
    else if (type === DvtMarker.PLUS) {
      var wThird = w / 3;
      var wTwoThird = 2 * wThird;
      var hThird = h / 3;
      var hTwoThird = 2 * hThird;

      ar.push(x + wThird);
      ar.push(y);
      ar.push(x + wTwoThird);
      ar.push(y);
      ar.push(x + wTwoThird);
      ar.push(y + hThird);
      ar.push(x + w);
      ar.push(y + hThird);
      ar.push(x + w);
      ar.push(y + hTwoThird);
      ar.push(x + wTwoThird);
      ar.push(y + hTwoThird);
      ar.push(x + wTwoThird);
      ar.push(y + h);
      ar.push(x + wThird);
      ar.push(y + h);
      ar.push(x + wThird);
      ar.push(y + hTwoThird);
      ar.push(x);
      ar.push(y + hTwoThird);
      ar.push(x);
      ar.push(y + hThird);
      ar.push(x + wThird);
      ar.push(y + hThird);
      ar.push(x + wThird);
      ar.push(y);
      this._setPolygon(ar);
    }
  }
}

/**
  *  Returns the default scale of the marker used to force it to the 
  *  reference size.
  *  @type number
  */
DvtSvgMarker.prototype.getDefaultScale = function()
{
   return this._defaultScale;
};

/**
  *  Returns the type of the marker (such as {@link DvtMarker#CIRCLE}.
  *  @type number
  */
DvtSvgMarker.prototype.getType = function()
{
   return  this._type ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setCx = function(cx)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'cx', cx) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setCy = function(cy)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'cy', cy) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setX = function(x)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'x', x) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setY = function(y)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'y', y) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setWidth = function(w)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'width', w) ;
} ;

/**
 * @private
  */
DvtSvgMarker.prototype._setHeight = function(h)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'height', h) ;
} ;

/**
 * @private
  */
DvtSvgMarker.prototype._setRadius = function(r)
{
   DvtSvgUtils.setAttrNullNS(this._elem, 'r', r) ;
} ;

/**
 *   @private
 */
DvtSvgMarker.prototype._setPolygon = function(ar)
{
   var sPoints = DvtSvgShapeUtils.convertPointsArray(ar);
   DvtSvgUtils.setAttrNullNS(this._elem, 'points', sPoints) ;
} ;

/**
 *   @private
 */
DvtSvgMarker.prototype._setCmds = function(cmds)
{
   if (cmds !== this._cmds) {
     this._cmds  = cmds ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'd', cmds) ;
   }
} ;


DvtSvgMarker.prototype.UpdateMarkerImage = function(imgSrc) {
  this.setSource(imgSrc);
}


/**
 * Updates the marker image source based on the current selection state
 * @param {string} src The image uri to set for the current marker state
 */
DvtSvgMarker.prototype.setSource = function(src)
{
  DvtSvgUtils.setAttrNS(this._elem, DvtSvgImage.XLINK_NS, 'xlink:href', src);
}
/**
 * @override
 */
DvtSvgMarker.prototype.GetAttributesTransferableToGroup = function() {
  var attrNames = DvtSvgContainer.AttributesTransferableToGroup.slice(0);
  // Check to see if matrix set since we don't transfer the 'transform' attr, bc it affects the clip path for custom markers.
  if (!this.getObj().getMatrix()) {
    var transformIndex = DvtArrayUtils.getIndex(attrNames, 'transform');
    attrNames.splice(transformIndex, 1);
  }
  var visibilityIndex = DvtArrayUtils.getIndex(attrNames, 'visibility');
  attrNames.splice(visibilityIndex, 1);
  return attrNames;
}

/**
 * Sets the position and size of the underlay for all but human markers
 * @private
 */
DvtSvgMarker.prototype._positionUnderlay = function(x, y, w, h)
{
    //Underlays cannot be custom, plus, or human shapes
    var type = this._underlay.getType();
    var radius = Math.max(w, h)/2;
    var pad;
    var ar = [];
    // Padding for triangles
    var triBottomPad = radius*.4;
    var triTipPad = + 1.6*radius;

    if (type === DvtMarker.SQUARE) {
        pad = radius*.5;
        this._underlay._setX(x - pad);
        this._underlay._setY(y - pad);
        this._underlay._setWidth(2*(radius + pad));
        this._underlay._setHeight(2*(radius + pad));
    }
    else if (type === DvtMarker.CIRCLE) {
        pad = radius*.7;
        this._underlay._setCx(x + w/2);
        this._underlay._setCy(y + h/2);
        this._underlay._setRX(radius + pad);
        this._underlay._setRY(radius + pad);
    }
    else if (type === DvtMarker.TRIANGLE_UP) {  
      pad = radius * 1.3;
      ar.push(x - pad);
      ar.push(y + 2*radius + triBottomPad);
      ar.push(x + radius);
      ar.push(y - triTipPad);
      ar.push(x + 2*radius + pad);
      ar.push(y + 2*radius + triBottomPad);
      this._underlay._setPolygon(ar);
    }
    else if (type === DvtMarker.TRIANGLE_DOWN) {
      pad = radius * 1.3;
      ar.push(x - pad);
      ar.push(y - triBottomPad);
      ar.push(x + 2*radius + pad);
      ar.push(y - triBottomPad);
      ar.push(x + radius);
      ar.push(y + 2*radius + triTipPad);
      this._underlay._setPolygon(ar);
    }
    else if (type === DvtMarker.DIAMOND) {
      pad = radius * 1.1;
      ar.push(x - pad);
      ar.push(y + radius);
      ar.push(x + radius);
      ar.push(y - pad);
      ar.push(x + 2*radius + pad);
      ar.push(y + radius);
      ar.push(x + radius);
      ar.push(y + 2*radius + pad);
      this._underlay._setPolygon(ar);
    }
}

/**
 * Sets the position and size of the underlay for human markers
 * @private
 */
DvtSvgMarker.prototype._positionHumanUnderlay = function(x, y, w, h)
{
    //Underlays cannot be custom, plus, or human shapes
    var type = this._underlay.getType();
    var radius = Math.max(w, h)/2;
    var pad;
    var ar = [];
    // Padding for triangles
    var triBottomPad = radius*.2;
    var triTipPad = + 0.65*radius;

    if (type === DvtMarker.SQUARE) {
        pad = radius*.15;
        this._underlay._setX(x - pad);
        this._underlay._setY(y - pad);
        this._underlay._setWidth(2*(radius + pad));
        this._underlay._setHeight(2*(radius + pad));
    }
    else if (type === DvtMarker.CIRCLE) {
        pad = radius*.2;
        this._underlay._setCx(x + w/2);
        this._underlay._setCy(y + h/2);
        this._underlay._setRX(radius + pad);
        this._underlay._setRY(radius + pad);
    }
    else if (type === DvtMarker.TRIANGLE_UP) {  
      pad = radius * 0.5;
      ar.push(x - pad);
      ar.push(y + 2*radius + triBottomPad);
      ar.push(x + radius);
      ar.push(y - triTipPad);
      ar.push(x + 2*radius + pad);
      ar.push(y + 2*radius + triBottomPad);
      this._underlay._setPolygon(ar);
    }
    else if (type === DvtMarker.TRIANGLE_DOWN) {
      pad = radius * 0.5;
      ar.push(x - pad);
      ar.push(y - triBottomPad);
      ar.push(x + 2*radius + pad);
      ar.push(y - triBottomPad);
      ar.push(x + radius);
      ar.push(y + 2*radius + triTipPad);
      this._underlay._setPolygon(ar);
    }
    else if (type === DvtMarker.DIAMOND) {
      pad = radius * 0.4;
      ar.push(x - pad);
      ar.push(y + radius);
      ar.push(x + radius);
      ar.push(y - pad);
      ar.push(x + 2*radius + pad);
      ar.push(y + radius);
      ar.push(x + radius);
      ar.push(y + 2*radius + pad);
      this._underlay._setPolygon(ar);
    }
}

/**  Sets the underlay for markers
 *  @param {string} ut underlay type
 *  @param {string} uc fill color of the underlay
 *  @param {number} ua fill alpha of the underlay
 */
DvtSvgMarker.prototype.setUnderlay = function(ut, uc, ua)
{
    var context = this.getObj().getCtx();
    this._underlay = context.getImplFactory().newMarker(ut);
    this._underlay.setFill(new DvtSolidFill(uc, ua));
    this._underlay.setObj(this.getObj());
    if (this.getType() === DvtMarker.HUMAN) {
        this._positionHumanUnderlay(this._x, this._y, 
                                    this._w, this._h);
    } else {
        this._positionUnderlay(this._x, this._y, 
                               this._w, this._h);
    }
    
    // add the underlay to the group elem explicitly because behavior of addChildAt might change
    this.CreateChildGroupElem(false);    
    var existingNode = this._childGroupElem.childNodes[0];
    // BUG #12661320: IE9 cannot handle a value of undefined in insertBefore.  Set to null in such a case. 
    if (!existingNode)
      existingNode = null;
    this._childGroupElem.insertBefore(this._underlay.getOuterElem(), existingNode);
}


/*---------------------------------------------------------------------*/
/*   getUnderlay()                                                     */
/*---------------------------------------------------------------------*/
/**  Gets the underlay for markers
 */
DvtSvgMarker.prototype.getUnderlay = function() 
{
  return this._underlay;
}

/**
 * Sets whether mouse events are enabled on this object.
 * @param {boolean} whether mouse events are enabled
 */
DvtSvgMarker.prototype.setMouseEnabled = function(bEnabled)
{
  DvtSvgMarker.superclass.setMouseEnabled.call(this, bEnabled);
  if (this._childGroupElem) {
      var val;
      if (bEnabled)
      {
        val = "visiblePainted";
      }
      else
      {
        val = "none";
      }
      DvtSvgUtils.setAttrNullNS(this._childGroupElem, "pointer-events", val);
  }
};

/**  Changes the shape to an outline shape format.  Used for legend
  *  markers that represent a hidden state for the associated series risers.
  *  @param {String} color Border color for hollow shape in format of #aarrggbb
  *  @param {number} strokeWidth Stroke width used for shapes that were transofrmed (optional)
  *  @override
  */
DvtSvgMarker.prototype.setHollow = function(color, strokeWidth)
{
    DvtSvgMarker.superclass.setHollow.call(this, color, strokeWidth);
};


DvtSvgMarker.prototype._setCustomMarker = function(markerDef, x, y, sx, sy)
{
  if (this._isMultiPaths()) {
    var root = this._cloneMultiPaths(markerDef, x, y, sx, sy);
    this.getObj().addChild(root);

    // return container of multi paths
    return root;
  }
  else {
    this._setSingleShape(markerDef, x, y, sx, sy);
    return null;
  }
} ;


DvtSvgMarker.prototype._setSingleShape = function(markerDef, x, y, sx, sy)
{
  var defImpl = markerDef.getImpl();
  var type = defImpl.getElem().nodeName;

  if (type == DvtSvgMarker.MARKER_PATH_ELEM_NAME) {
    this._setCmds(DvtPathUtils.transformPath(defImpl._sCmds, x, y, sx, sy));
  }
  /*
  else if (type == DvtSvgMarker.MARKER_CIRCLE_ELEM_NAME ||
           type == DvtSvgMarker.MARKER_ELLIPSE_ELEM_NAME) {
    this._setCx(markerDef.getCx());
    this._setCy(markerDef.getCy());
    this._setRadius(markerDef.getRadius());
  }

  else if (type == DvtSvgMarker.MARKER_LINE_ELEM_NAME) {
    this._setX1(defImpl.getX1());
    this._setX2(defImpl.getX2());
    this._setY1(defImpl.getY1());
    this._setY2(defImpl.getY2());
  }
  else if (type == DvtSvgMarker.MARKER_POLYGON_ELEM_NAME) {
    this._setPoints(defImpl._sPoints);
  }
  else if (type == DvtSvgMarker.MARKER_POLYLINE_ELEM_NAME) {
    this._setPoints(defImpl._sPoints);
  }
  else if (type == DvtSvgMarker.MARKER_RECT_TYPE_ELEM_NAME) {
    this._setX(markerDef.getX());
    this._setY(markerDef.getY());
    this._setWidth(markerDef.getWidth());
    this._setHeight(markerDef.getHeight());
  }
  */

  var fill = defImpl.getFill();
  if (fill) {
    this.setFill(fill);
  }
  var alpha = defImpl.getAlpha();
  if (alpha) {
    this.setAlpha(alpha);
  }
  var stroke = defImpl.getStroke();
  if (stroke) {
    var scaledStroke = stroke.clone();
    scaledStroke.setWidth(Math.min(sx, sy) * scaledStroke.getWidth());
    this.setStroke(scaledStroke);
  }
} ;


/**
 *   @private
 */
DvtSvgMarker.prototype._setPoints = function(points)
{
   if (points !== this._points) {
     this._points  = points ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'points', points);
   }
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setX1 = function(x1)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'x1', x1) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setY1 = function(y1)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'y1', y1) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setX2 = function(x2)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'x2', x2) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setY2 = function(y2)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'y2', y2) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setRX = function(rx)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'rx', rx) ;
} ;

/**
 * @private
 */
DvtSvgMarker.prototype._setRY = function(ry)
{
  DvtSvgUtils.setAttrNullNS(this._elem, 'ry', ry) ;
} ;


/**
 * @private
 */
DvtSvgMarker.prototype._cloneMultiPaths = function(markerDef, x, y, sx, sy) {
  var context = this.getObj().getCtx();
  var root = new DvtContainer(context, markerDef.getId() + "_x");

  var childCnt = markerDef.getNumChildren();
  var childDef;
  var child;
  for (var i = 0; i < childCnt; i++) {
    childDef = markerDef.getChildAt(i);
    child = new DvtPath(context, DvtPathUtils.transformPath(childDef.getCmds(), x, y, sx, sy), childDef.getId());

    if (childDef.getFill()) {
      child.setFill(childDef.getFill());
    }
    if (childDef.getAlpha()) {
      child.setAlpha(childDef.getAlpha());
    }
    if (childDef.getStroke()) {
      var scaledStroke = childDef.getStroke().clone();
      scaledStroke.setWidth(Math.min(sx, sy) * scaledStroke.getWidth());
      child.setStroke(scaledStroke);
    }
    root.addChild(child);
  }

  return root;
}

/**
 * @override
 */
DvtSvgMarker.prototype.addChild = function(obj) {
  // if this marker has multi paths, don't add an additonal childGroupElem
  if (this._isMultiPaths()) {
    DvtSvgUtils.appendChildElem(this._elem, obj.getOuterElem()) ;
  }
  else {
    DvtSvgMarker.superclass.addChild.call(this, obj);
  }
};


DvtSvgMarker.prototype._isMultiPaths = function() {
  return (this.getElem().nodeName == "g" && this.getType() != DvtMarker.IMAGE);
};

/**
 * @override
 */
DvtSvgMarker.prototype.getDimensions = function() {
  // Added in order to prevent getDimensions returning null or a 0 width and height while waiting for an image load
  if (this._type == DvtMarker.IMAGE) {
    var w = this.getObj().getScaledWidth();
    var h = this.getObj().getScaledHeight()
    return new DvtRectangle(this._x, this._y, w, h);
  } else {
    return DvtSvgMarker.superclass.getDimensions.call(this);
  }
}

/**
 * @override
 */
DvtSvgMarker.prototype.GetElemDimensionsWithStroke = function() {
  if (this._type == DvtMarker.IMAGE)
    return this.getDimensions(); // images don't have borders
  else
    return DvtSvgMarker.superclass.GetElemDimensionsWithStroke.call(this);
}
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*-------------------------------------------------------------------------*/
/*    DvtSvgOval       Svg implementation of base elliptical shape         */
/*-------------------------------------------------------------------------*/
/**
  *   Creates an elliptical shape implemented by SVG.
  *   @extends DvtSvgCircle
  *   @class  DvtSvgOval Creates an elliptical shape implemented by SVG. Do not create directly
  *   - use {@link DvtOval}.
  *   <p>
  *   Example:<br><br><code>
  *   var Oval = new DvtOval(context, 50, 50, 20, 40) ;<br>
  *   </code>
  *   @constructor  
  *   @param {number} cx  The center x position.
  *   @param {number} cy  The center y position.
  *   @param {number} rx  The horizontal radius of the ellipse.
  *   @param {number} ry  The vertical radius of the ellipse.
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSvgOval = function(cx, cy, rx, ry, id)
{
   this._Init(cx, cy, rx, ry, id) ;
};

DvtObj.createSubclass(DvtSvgOval, DvtSvgCircle, "DvtSvgOval") ;



/*-------------------------------------------------------------------------*/
/*  _Init()                                                                */
/*-------------------------------------------------------------------------*/
/** @private */

DvtSvgOval.prototype._Init = function(cx, cy, rx, ry, id)
{
   DvtSvgOval.superclass._Init.call(this, cx, cy, rx, id, 'ellipse') ;

   this.setRx(rx);
   this.setRy(ry);
   this.setRadius(null) ;
} ;


/*-------------------------------------------------------------------------*/
/*   get/setRx()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the horizontal radius of the ellipse.
  *  @type number
  */
DvtSvgOval.prototype.getRx = function()
{
   return this._rx ;
} ;

/**
  *  Sets the horizontal radii of the ellipse.
  *  @param {number} rx  The horizontal radius of the ellipse.
  */
DvtSvgOval.prototype.setRx = function(rx)
{
   if (rx !== this._rx) {
     this._rx  = rx ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'rx', this._rx) ;
   }
} ;


/*-------------------------------------------------------------------------*/
/*   get/setRy()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the vertical radius of the ellipse.
  *  @type number
  */
DvtSvgOval.prototype.getRy = function()
{
   return this._ry ;
} ;

/**
  *  Sets the vertical radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  */
DvtSvgOval.prototype.setRy = function(ry)
{
   if (ry !== this._ry) {
     this._ry  = ry ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'ry', this._ry) ;
   }
} ;

// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/**
  *   Creates a shape using SVG path commands implemented for SVG.
  *   @extends DvtSvgShape
  *   @class DvtSvgPath  Creates a shape using SVG path commands implemented for
  *   SVG.  Do not create directly, use {@link DvtPath}.
  *   <p>Example:<br><br><code>
  *   var  path = new DvtPath(context, mycmds) ;<br>
  *   </code>
  *   @constructor  
  *   @param {Object} cmds  Optional string of SVG path command (see comment for
  *                         {@link DvtPath#setCmds}),
  *                         or an array containing consecutive command and coordinate
  *                          entries (see comment for {@link DvtPath#setCommands}).
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSvgPath = function(cmds, id)
{
   this._Init(cmds, id) ;
};

DvtObj.createSubclass(DvtSvgPath, DvtSvgShape, "DvtSvgPath") ;

/** @private */
DvtSvgPath.prototype._Init = function(cmds, id)
{
   DvtSvgPath.superclass._Init.call(this, id, 'path') ;

   if (DvtArrayUtils.isArray(cmds)) {
     this.setCmds(DvtPathUtils.getPathString(cmds)) ;
   }
   else {
     this.setCmds(cmds) ;
   }
} ;

/**
  *  Gets the path from a string of SVG commands in SVG "d" attribute format.
  *  @param {String} cmds A string containing the SVG commands sequences.
  */
DvtSvgPath.prototype.getCmds = function()
{
   return this._sCmds ;
} ;
/**
  *  Sets the path from a string of SVG commands in SVG "d" attribute format.
  *  @param {String} cmds A string containing the SVG commands sequences.
  */
DvtSvgPath.prototype.setCmds = function(cmds)
{
   this._sCmds  = cmds ;
   if (cmds) {
     DvtSvgUtils.setAttrNullNS(this._elem, 'd', cmds) ;
   }
} ;
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*-------------------------------------------------------------------------*/
/*   DvtSvgPolygon         SVG Implementation of Base Polygon shape        */
/*-------------------------------------------------------------------------*/
/**
  *   Creates a polygon from an array of (x,y) coordinates.
  *   SVG implementation for DvtPolygon which creates a shape of connected line segments.
  *   @extends DvtSvgShape
  *   @class DvtSvgPolygon
  *   @constructor  
  *   @param {Array} arPoints  An array of x, y pairs of coordinates.
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSvgPolygon = function(arPoints, id)
{
   this._Init(arPoints, id) ;
};

DvtObj.createSubclass(DvtSvgPolygon, DvtSvgShape, "DvtSvgPolygon") ;





/*-------------------------------------------------------------------------*/
/*   _Init()                                                               */
/*-------------------------------------------------------------------------*/
/** @private */
DvtSvgPolygon.prototype._Init = function(arPoints, id)
{
   DvtSvgPolygon.superclass._Init.call(this, id, 'polygon') ;

   this.setPoints(arPoints) ;

} ;

/*-------------------------------------------------------------------------*/
/*   get/setPoints()            Gets/Sets the polygon points               */
/*-------------------------------------------------------------------------*/

DvtSvgPolygon.prototype.getPoints = function()
{
   return  this._arPoints ;
} ;

/**
  *   Sets the polygon points from an array of x,y coordinate pairs.
  *   @param {Array} arPoints  An array of x, y pairs of coordinates.
  */
DvtSvgPolygon.prototype.setPoints = function(arPoints)
{
   this._arPoints = arPoints ;
   this._sPoints = DvtSvgShapeUtils.convertPointsArray(arPoints);
   DvtSvgUtils.setAttrNullNS(this._elem, 'points', this._sPoints) ;
} ;
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*--------------------------------------------------------------------*/
/*   DvtSvgPolyline         SVG Implementation of DvtPolyline         */
/*--------------------------------------------------------------------*/
/**
  *   Svg implementation for DvtPolyline which creates a series of joined
  *   lines whose points are specified by an array of x,y pairs).
  *   @extends DvtSvgShape
  *   @class DvtSvgPolyline
  *   @constructor  
  *   @param {Array} arPoints  An array of point coordinates.
  *   @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *   <p>
  *   Example:<br><br><code
  *   var points = [10,20,40,34,59,128, . . .] ;<br>
  *   var polyline = new DvtPolyline(context, points);<br>
  *    </code>
  */
var DvtSvgPolyline = function(arPoints, id)
{
   this._Init(arPoints, id) ;
};

DvtObj.createSubclass(DvtSvgPolyline, DvtSvgShape, "DvtSvgPolyline") ;





/*--------------------------------------------------------------------*/
/*   _Init()                                                          */
/*--------------------------------------------------------------------*/

DvtSvgPolyline.prototype._Init = function(arPoints, id)
{
   DvtSvgPolyline.superclass._Init.call(this, id, 'polyline') ;

   DvtSvgUtils.setAttrNullNS(this._elem, 'fill', 'none') ;
   this.setPoints(arPoints) ;

} ;


/*-------------------------------------------------------------------------*/
/*   get/setPoints()            Gets/Sets the polygon points               */
/*-------------------------------------------------------------------------*/

DvtSvgPolyline.prototype.getPoints = function()
{
   return  this._arPoints ;
} ;

/**
  *   Sets the polyline points from an array of x,y coordinate pairs.
  *   @param {Array} arPoints  An array of x, y pairs of coordinates.
  */
DvtSvgPolyline.prototype.setPoints = function(arPoints)
{
   this._arPoints = arPoints ;
   this._sPoints = DvtSvgShapeUtils.convertPointsArray(arPoints);
   DvtSvgUtils.setAttrNullNS(this._elem, 'points', this._sPoints) ;
} ;
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*---------------------------------------------------------------------*/
/*    DvtSvgRect          Svg implementation for base shape DvtRect    */
/*---------------------------------------------------------------------*/
/**
  *   Svg implementation for DvtRect.
  *   @extends DvtSvgShape
  *   @class DvtSvgRect
  *   @constructor  
  *   May be specified as individual values or using a DvtRectangle object.
  *   <p>
  *   Example:<br><br><code>
  *   rect = new DvtRect(context, 10, 10, 50, 100) ; &nbsp; @nbsp;  or<br>
  *
  *   rect = new DvtRect(context, myRect) ;  &nbsp; &nbsp;  where myRect = new DvtRectangle(10, 10, 50, 100);<br>
  *   </code>
  */
var  DvtSvgRect = function(x, y, w, h, id)
{
   this._Init(x, y, w, h, id) ;
};

DvtObj.createSubclass(DvtSvgRect, DvtSvgShape, "DvtSvgRect") ;

DvtSvgRect._cssAttrs = 
[
  "background-color",
  "border-color",
  "border-width"
];

/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/** @private */
DvtSvgRect.prototype._Init = function(x, y, w, h, id)
{
   DvtSvgRect.superclass._Init.call(this, id, 'rect') ;

   this.setX(x);
   this.setY(y);
   this.setWidth(w);
   this.setHeight(h);
} ;

/*---------------------------------------------------------------------*/
/*   get/setX()                                                        */
/*---------------------------------------------------------------------*/

DvtSvgRect.prototype.getX = function()
{
   return this._x ;
} ;
DvtSvgRect.prototype.setX = function(x)
{
   if (x !== this._x) {
     this._x  = x ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'x', this._x) ;
   }
} ;


/*---------------------------------------------------------------------*/
/*   get/setY()                                                        */
/*---------------------------------------------------------------------*/

DvtSvgRect.prototype.getY = function()
{
   return this._y ;
} ;
DvtSvgRect.prototype.setY = function(y)
{
   if (y !== this._y) {
     this._y  = y ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'y', this._y) ;
   }
} ;


/*---------------------------------------------------------------------*/
/*   get/setWidth()                                                    */
/*---------------------------------------------------------------------*/

DvtSvgRect.prototype.getWidth = function()
{
   return this._w ;
} ;

/**
  *  Sets the width of the rectangle.
  *  @param {number} w  The width of the rectangle.
  */
DvtSvgRect.prototype.setWidth = function(w)
{
   if (w !== this._w) {
     this._w  = w ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'width', this._w) ;
   }
} ;

/*---------------------------------------------------------------------*/
/*   get/setHeight()                                                   */
/*---------------------------------------------------------------------*/
/**
  *  Returns the height of the rectangle.
  *  @type number
  */
DvtSvgRect.prototype.getHeight = function()
{
   return  this._h ;
} ;

/**
  *  Sets the height of the rectangle.
  *  @param {number} h  The height of the rectangle.
  */
DvtSvgRect.prototype.setHeight = function(h)
{
   if (h !== this._h) {
     this._h  = h ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'height', this._h) ;
   }
} ;

/*---------------------------------------------------------------------*/
/*   get/setRx()                                                       */
/*---------------------------------------------------------------------*/

DvtSvgRect.prototype.getRx = function()
{
   return this._rx ;
} ;
DvtSvgRect.prototype.setRx = function(rx)
{
   if (rx !== this._rx) {
     this._rx  = rx ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'rx', this._rx) ;
   }
} ;

/*---------------------------------------------------------------------*/
/*   get/setRy()                                                       */
/*---------------------------------------------------------------------*/

DvtSvgRect.prototype.getRy = function()
{
   return this._ry ;
} ;
DvtSvgRect.prototype.setRy = function(ry)
{
   if (ry !== this._ry) {
     this._ry  = ry ;
     DvtSvgUtils.setAttrNullNS(this._elem, 'ry', this._ry) ;
   }
} ;

/**
 * Sets the DvtCSSStyle of this object.
 * @param {DvtCssStyle} style The DvtCSSStyle of this object.
 */
DvtSvgRect.prototype.setCSSStyle = function(style)
{
  DvtSvgRect.superclass.setCSSStyle.call(this, style);
  
  //calling this results in fill="none" being removed
  //on rects that don't apply a css style, which
  //results in them being filled black
  //DvtSvgRect._removeDefaultAttributes(this._elem);
  
  var elem = this._elem;
  if (style)
  {
    var val = style["background-color"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "fill", val);
    }
    val = style["border-color"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "stroke", val);
    }
    val = style["border-width"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "stroke-width", val);
    }

    //bug 13826956 - border-radius css property not supported when used inside <dvt:node>
    val = style["border-radius"];
    if (val) {
      var radArr = DvtStringUtils.trim(val).split(" ");
      if (radArr.length > 0 && radArr[0]) {
        this.setRx(radArr[0]);
      }
      if (radArr.length > 1 && radArr[1]) {
        this.setRy(radArr[1]);
      }
    }
  }
  else
  {
    DvtSvgUtils.removeAttrNullNS(this._elem, "style");
  }
};

DvtSvgRect._removeDefaultAttributes = function(elem)
{
  DvtSvgUtils.removeAttrNullNS(elem,"fill");
  DvtSvgUtils.removeAttrNullNS(elem,"stroke");
  DvtSvgUtils.removeAttrNullNS(elem,"stroke-width");
};
// Copyright (c) 2008, 2023, Oracle and/or its affiliates.
/*-------------------------------------------------------------------------*/
/*   DvtSvgText        SVG implementation of text "shape"                  */
/*-------------------------------------------------------------------------*/
/**
 * Creates an instance of DvtSvgText.
 * @class DvtSvgText
 * @extends DvtSvgShape
 * @constructor
 * @param {DvtContext} context
 * @param textStr {string} the text string
 * @param x {number} x the x position
 * @param y {number} y the y position
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 */
var  DvtSvgText = function(context, textStr, x, y, id)
{
  this._Init(context, textStr, x, y, id) ;
};

DvtObj.createSubclass(DvtSvgText, DvtSvgShape, "DvtSvgText") ;


/**
 * Initializes this instance of DvtText.
 * @param {DvtContext} context
 * @param textStr {string} the text string
 * @param x {number} x the x position
 * @param y {number} y the y position
 * @param id {string} the id for this object
 */
DvtSvgText.prototype._Init = function(context, textStr, x, y, id)
{
  DvtSvgText.superclass._Init.call(this, id, 'text') ;
  this._context = context;
  this.setTextString(textStr);
  this.setX(x);
  this.setY(y);
  
  // TODO this should be defined elsewhere
  // cursor is needed for chrome, but should be dependent on interactivity
  DvtSvgUtils.setAttrNullNS(this.getElem(), "font-family", "tahoma, sans-serif");
  DvtSvgUtils.setAttrNullNS(this.getElem(), "fill", "rgb(0,0,0)");  
  
  // fix for bug 14528150 (the chrome case) and 14297988 (the ie case)
  if (DvtAgent.isRightToLeft(context)) {
    if (DvtAgent.isPlatformIE())
      this.setTextString("\u202B"+textStr);
    else if (DvtSvgText.needsTextAnchorAdjustment(context))
      this.alignStart();
    else
      DvtSvgUtils.setAttrNullNS(this.getElem(), "unicode-bidi", "embed");
  }
 
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  this._baseline = null;
  //FIX BUG 16856961: additional pixel offset for baseline, currently only
  //specified by DvtSvgTextArea subclass
  this._baselineOffset = null;

  //  For edit mode 
  this._bEditMode   = false ;
  this._editStartCallback = null;
  this._editEndCallback = null;
  this._editPxWidth ;
  this._editElem    = null ;    // <textarea> elem
  this._editBorder  = false ;
  this._editTooltip = null ;
} ;

/**
 * Returns the text string for this text object.
 * @return {string} the text string
 */ 
DvtSvgText.prototype.getTextString = function() {
  var txt ;
  if (this._bEditMode && this._editElem) {      // if in edit mode
     txt = this._editElem.value ;
  }
  else {
    var textNode = this.GetTextElem().firstChild;
    if (textNode) {
      txt = textNode.nodeValue;
    }
  }
  return txt ;
} ;

/**
 * Sets the text string for this text object.
 * @param {string} textStr the text string
 */
DvtSvgText.prototype.setTextString = function(textStr)
{
  // Update the text node if it is already created
  var textNode = this.GetTextElem().firstChild;
  if(textNode !== null) {
    textNode.nodeValue = textStr;
  }
  else { // Otherwise create it
    textNode = document.createTextNode(textStr);
    DvtSvgUtils.appendChildElem(this.GetTextElem(), textNode);
  }

  if (this._editElem) {             // if an edit element, change its text also.
    this._editElem.value = textStr ;
  }

} ;


/**
 * Sets the text angle. See also {@link DvtSvgText#setRotatePoint}.
 * @param {number} a the angle in degrees. Positive angles rotate counter-clockwise.
 */
DvtSvgText.prototype.doNotUseSetAngle = function(a)
{
   this._angle = (a % 360) ;

   if (this._angle > 0) {
     this._angle = 360 - this._angle ;    // for svg, positive angles rotate clockwise
    }

   if (this._angle != 0) {
     if (this._cx && this._cy) {
       DvtSvgUtils.setAttrNullNS(this.getElem(), 'transform', "rotate(" + this._angle + " " + 
                                           this._cx + "," + this._cy + ")") ;
    }
  }
  else {
    DvtSvgUtils.removeAttrNullNS(this.getElem(), 'transform');
    if (DvtAgent.isPlatformIE()) { // bug 14622256, prev removeAttributeNS()
      DvtSvgUtils.setAttrNullNS(this.getElem(), 'transform', null);        // fails for IE9 (9.0.8112.16421)
    }
  }
}; 


/**
 * Sets the rotation point for angled text (see {@link DvtSvgText#setAngle}).
 * @param {number} cx the rotation point x-coordinate.
 * @param {number} cy the rotation point y-coordinate.
 */
DvtSvgText.prototype.doNotUseSetRotatePoint = function(cx, cy)
{
  this._cx = cx ;
  this._cy = cy ;
  if (this._angle) {
    DvtSvgUtils.setAttrNullNS(this.getElem(), 'transform', "rotate(" + this._angle + " " + cx + "," + cy + ")") ;
  }
}; 


/**
 * Gets the x position for this text object.
 * @returns {number}  the x position
 */
DvtSvgText.prototype.getX = function()
{
  return  this._x ;
};

/**
 * Sets the x position for this text object.
 * @param {number} x the x position
 */
DvtSvgText.prototype.setX = function(x)
{
  if (x !== this._x) {
    this._x  = x ;
    DvtSvgUtils.setAttrNullNS(this.getElem(), 'x', x);
  }
}; 

/**
 * Gets the y position for this text object.
 * @returns {number}  the y position
 */
DvtSvgText.prototype.getY = function()
{
  return  this._y ;
};
/**
 * Sets the y position for this text object.
 * @param {number} y the y position
 */
DvtSvgText.prototype.setY = function(y)
{
  if (y !== this._y) {
    this._y  = y ;
    DvtSvgUtils.setAttrNullNS(this.getElem(), 'y', y);
  }
};

/**
 * Sets the font size.
 * @param {number} fontSize the font size
 */
DvtSvgText.prototype.setFontSize = function(fontSize)
{
  DvtSvgUtils.setAttrNullNS(this.getElem(), 'font-size', fontSize);

  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  this._setMatrix(this.getMatrix(), fontSize);
};

/**
 * Aligns the left side of the text to the x coordinate. Note: This does not always correspond to what the browser
 * considers a "start" alignment, as we work around issues in rtl locales to provide a consistent API.
 */
DvtSvgText.prototype.alignStart = function() {
  // Bug 17776065: When html dir="rtl", Webkit and FF25+ treat the right side of the text as the start, and the left 
  // side of the text as end.  Our API always treats the left side as start, so we need to adjust based on agent.
  var bAdjust = DvtSvgText.needsTextAnchorAdjustment(this._context);
  DvtSvgUtils.setAttrNullNS(this.getElem(), "text-anchor", bAdjust ? "end" : "start");
}

/**
 * Aligns the center of the text to the x coordinate.
 */
DvtSvgText.prototype.alignCenter = function() {
  DvtSvgUtils.setAttrNullNS(this.getElem(), "text-anchor","middle");
}

/**
 * Aligns the right side of the text to the x coordinate. Note: This does not always correspond to what the browser
 * considers an "end" alignment, as we work around issues in rtl locales to provide a consistent API.
 */
DvtSvgText.prototype.alignEnd = function() {
  // Bug 17776065: When html dir="rtl", Webkit and FF25+ treat the right side of the text as the start, and the left 
  // side of the text as end.  Our API always treats the left side as start, so we need to adjust based on agent.
  var bAdjust = DvtSvgText.needsTextAnchorAdjustment(this._context);
  DvtSvgUtils.setAttrNullNS(this.getElem(), "text-anchor", bAdjust ? "start" : "end");
}

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtSvgText.prototype.alignTop = function() {
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  if (DvtAgent.isPlatformIE()){
    //+ font-size
    this.SetBaseline(1);
  }
  else {
    this.SetDominantBaselineAttr("text-before-edge");
  }
};

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtSvgText.prototype.alignMiddle = function() {
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  if (DvtAgent.isPlatformIE()){
    //+ 2/5 font-size
    this.SetBaseline(.4);
  }
  else {
    this.SetDominantBaselineAttr("middle");
  }
};

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtSvgText.prototype.alignBottom = function() {
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  if (DvtAgent.isPlatformIE()){
    //+ 1/5 font-size
    this.SetBaseline(.2);
  }
  else {
    this.SetDominantBaselineAttr("text-after-edge");
  }
};

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtSvgText.prototype.alignBaseline = function() {
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  if (DvtAgent.isPlatformIE()){
    this.SetBaseline(0);
  }
  else {
    this.SetDominantBaselineAttr(null);
  }
};

/**
 * @protected
 * Save the baseline and adjust the matrix for vertical alignment in IE.
 */
DvtSvgText.prototype.SetBaseline = function(baseline) {
  this._baseline = baseline;
  this._setMatrix(this.getMatrix(), null);
}

/**
 * @protected
 * Set the dominant baseline for vertical alignment.
 */
DvtSvgText.prototype.SetDominantBaselineAttr = function(baseline) {
  if (baseline) {
    DvtSvgUtils.setAttrNullNS(this.getElem(), "dominant-baseline", baseline);
  }
  else {
    DvtSvgUtils.removeAttrNullNS(this.getElem(), "dominant-baseline");
  }
}

/**
 * Sets the text string for this text object.
 * @param {string} text the text string
 */
DvtSvgText.prototype.setText = function(text) {
  // Update the text node if it is already created
  var textNode = this.GetTextElem().firstChild;
  if(textNode !== null) {
    textNode.nodeValue = text;
  }
  else { // Otherwise create it
    textNode = document.createTextNode(text);
    DvtSvgUtils.appendChildElem(this.GetTextElem(), textNode);
  }

  if (this._bEditMode && this._editElem) {             // if in edit mode, also change the textarea
    this._editElem.value = text ;
  }
};

/**
 * @return the text string for this text object.
 */
DvtSvgText.prototype.getText = function() {
  if (this._bEditMode && this._editElem) {
    return this._editElem.value;
  }
  
  var textNode = this.GetTextElem().firstChild;
  if(textNode) {
    return textNode.nodeValue;
  }
};

/**
 * Sets the DvtCSSStyle of this object.
 * @param {DvtCSSStyle} style The DvtCSSStyle of this object.
 */
DvtSvgText.prototype.setCSSStyle = function(style)
{
  DvtSvgText.superclass.setCSSStyle.call(this, style);
  var elem = this.getOuterElem();

  if (style) {
    //NOTE: svg does not recognize css "color" attribute, use "fill" instead
    var val = style.color;
    if(val)
      DvtSvgUtils.setAttrNullNS(elem, "fill", val);
  
    val = style["font-family"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "font-family", val);
    }
    val = style["font-size"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "font-size", val);

      //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
      this._setMatrix(this.getMatrix(), val);
    }
    val = style["font-style"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "font-style", val);
    }
    val = style["font-weight"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "font-weight", val);
    }

    //NOTE: svg does not recognize css "text-align" attribute, 
    //call alignCenter, alignStart, alignEnd... if needed.
    //For multi line text, text-align is handled in DvtSvgTextArea

    val = style["text-decoration"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "text-decoration", val);
    }

    val = style["cursor"];
    if (val) {
      DvtSvgUtils.setAttrNullNS(elem, "cursor", val);
    }

    color = style.color;
  }
};

/**
 * Get the font styles.
 * @return {DvtCSSStyle} the font styles
 */
DvtSvgText.prototype.getFontStyles = function() {
  var cssStyle = new DvtCSSStyle();
  var fontFamily = DvtSvgUtils.getAttrNullNS(this.getElem(), DvtCSSStyle.FONT_FAMILY);
  if (!fontFamily) {
    fontFamily = "tahoma, sans-serif"; //this is default from DvtSvgText._Init()
  }
  cssStyle.setStyle(DvtCSSStyle.FONT_FAMILY, fontFamily);
  var fontSize = DvtSvgUtils.getAttrNullNS(this.getElem(), DvtCSSStyle.FONT_SIZE);
  if (!fontSize) {
    fontSize = "medium"; //this is default according to SVG 1.1 spec
  }
  cssStyle.setStyle(DvtCSSStyle.FONT_SIZE, fontSize);
  var fontStyle = DvtSvgUtils.getAttrNullNS(this.getElem(), DvtCSSStyle.FONT_STYLE);
  if (!fontStyle) {
    fontStyle = "normal"; //this is default according to SVG 1.1 spec
  }
  cssStyle.setStyle(DvtCSSStyle.FONT_STYLE, fontStyle);
  var fontWeight = DvtSvgUtils.getAttrNullNS(this.getElem(), DvtCSSStyle.FONT_WEIGHT);
  if (!fontWeight) {
    fontWeight = "normal"; //this is default according to SVG 1.1 spec
  }
  cssStyle.setStyle(DvtCSSStyle.FONT_WEIGHT, fontWeight);
  return cssStyle;
};


/**
 * Returns true if this text object is in editMode, else false.
 * @type boolean
 */
DvtSvgText.prototype.getEditMode = function()
{
    return this._bEditMode ;
};


/**
 * Sets the edit mode of this text object.
 * @param bEditMode {boolean} true if the text is to be editable, else false.
 *                            The mode may be changed at any time.
 * @param {function} editStartCallback  optional function to call when editing starts that takes the string as
 *        an argument and can optionally return a replacement string
 * @param {function} editEndCallback  optional function to call when editing ends that takes the string as
 *        an argument and can optionally return a replacement string
 */
DvtSvgText.prototype.setEditMode = function(bEditMode, editStartCallback, editEndCallback) {
  this._editStartCallback = editStartCallback;
  this._editEndCallback = editEndCallback;
  if (this._bEditMode == bEditMode) {
    return;
  }
  //FIX BUG 16901294: in edit mode, make this text a shape container and add a rect behind the text
  //to define the size of the edit box
  if (bEditMode) {
    var obj = this.getObj();
    var dims = obj.getDimensions();
    
    this.CreateChildGroupElem();
    this._editRectElem = DvtSvgShapeUtils.createElement("rect") ;
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "x", 0);
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "y", 0);
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "width", this._editPxWidth);
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "height", dims.h);
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "fill", "#ffffff");
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "fill-opacity", 0);
    DvtSvgUtils.setAttrNullNS(this._editRectElem, "cursor", "text");
    DvtSvgUtils.appendChildElem(this._childGroupElem, this._editRectElem);
  }
  else {
    this._childGroupElem.removeChild(this._editRectElem);
  }
  this._bEditMode = bEditMode;
};

//FIX BUG 16901294: 
/**
 * @protected
 * Set whether editable text is currently being edited.
 * @param {boolean}  bEditing  true if editing, false otherwise
 */
DvtSvgText.prototype.SetEditing = function(bEditing) {
  if (!this._bEditMode || bEditing == this._bEditing) {
    return;
  }
  var obj        =  this.getObj() ;
  var textElem   =  this.GetTextElem();
  var input ;                                   // textArea elem

  if ((!bEditing) && this._editElem)
  {                                             // change from edit to non-edit mode
     var editedText = this._editElem.value;
    //(NOTE: set the text on the thisDvtText before calling the _editEndCallback, because the
    //callback might change the text on this DvtText, and that should take precedence)
     this.setTextString(editedText) ;

     //call the callback and potentially get replacement text
     if (this._editEndCallback) {
       var retText = this._editEndCallback.call(null, editedText);
       if (retText) {
         this.setTextString(retText);
       }
     }
     
     //put the SVG text behind the _editRectElem
     this.getElem().insertBefore(textElem, this._editRectElem) ;

     if (this._bEventListener) {
       input = this._editElem ;
       //remove the listeners on the HTML text area
       if (this._htmlTextAreaListenerFunc) {
         DvtSvgUtils.removeDomEventListener(input, DvtKeyboardEvent.KEYDOWN,   this._htmlTextAreaListenerFunc, false);
         DvtSvgUtils.removeDomEventListener(input, DvtKeyboardEvent.KEYUP,     this._htmlTextAreaListenerFunc, false);
         DvtSvgUtils.removeDomEventListener(input, "keypress",  this._htmlTextAreaListenerFunc, false);
         DvtSvgUtils.removeDomEventListener(input, "textInput", this._htmlTextAreaListenerFunc, false);
         DvtSvgUtils.removeDomEventListener(input, "textinput", this._htmlTextAreaListenerFunc, false);
         this._htmlTextAreaListenerFunc = null;
       }
       //remove the blur listener on the HTML text area
       if (this._editBlurFunc) {
         DvtSvgUtils.removeDomEventListener(input, "blur", this._editBlurFunc, false);
         this._editBlurFunc = null;
       }
       this._bEventListener = false ;
     }
     //remove the HTML text area from its parent div AFTER removing listeners so that blur listener
     //does not get called due to removal from DOM
     if (this._editElem && this._editElem.parentNode) {
       this._editElem.parentNode.removeChild(this._editElem);
     }
     //This is commented out for now because when it is uncommented and a new HTML text area is created every time, 
     //if you enter some text and then click outside and then click back inside the text, the cursor appears at
     //the beginning of the text.  With this commented out, the cursor appears wherever it last was, which seems 
     //preferable.
     //this._editElem = null;
  }
  else                                       // change to editMode
  {
    var editText = this.getText();
    //create the HTML text area
    //(NOTE: set the text on the HTML text area before calling the _editStartCallback, because the
    //callback might change the text on this DvtText, and that should take precedence)
    if (! this._editElem) {
      input = this._createHtmlTextArea(obj, textElem, editText);
    }

    //call the callback and potentially get replacement text
    if (this._editStartCallback) {
      var retText = this._editStartCallback.call(null, editText);
      if (retText) {
        this.setTextString(retText);
      }
    }
    
    //remove the SVG text from the DOM
    this.getElem().removeChild(textElem) ;
    //FIX BUG 16901294: add the HTML text area to the SVG parent div so that it can be overlaid on top of SVG content
    if (this._editElem) {
      DvtSvgUtils.appendChildElem(obj.getCtx().getStage().getImpl().getSVGRoot().parentNode, this._editElem);
    }

    input = this._editElem ;
    var thisRef = this;
    //create a closure to redirect to the instance function so we have a valid "this" pointer in the listener
    this._htmlTextAreaListenerFunc = function(event) {
      thisRef._handleHtmlTextAreaKeyboardEvent(event);
    };
    //add listeners on the HTML text area
    DvtSvgUtils.addDomEventListener(input, DvtKeyboardEvent.KEYDOWN,   this._htmlTextAreaListenerFunc, false);
    DvtSvgUtils.addDomEventListener(input, DvtKeyboardEvent.KEYUP,     this._htmlTextAreaListenerFunc, false);
    DvtSvgUtils.addDomEventListener(input, "keypress",  this._htmlTextAreaListenerFunc, false);   // legacy event handler, works everywhere
    DvtSvgUtils.addDomEventListener(input, "textInput", this._htmlTextAreaListenerFunc, false);   // Safari and Chrome
    DvtSvgUtils.addDomEventListener(input, "textinput", this._htmlTextAreaListenerFunc, false);   // DOM Level 3 Events draft
    //create a closure to redirect to the instance function so we have a valid "this" pointer in the listener
    this._editBlurFunc = function(event) {
      thisRef._blurEditText();
    };
    //listen for blur event to know when editing has stopped
    DvtSvgUtils.addDomEventListener(input, "blur", this._editBlurFunc, false);
    this._bEventListener = true ;
  }
  //save value at end because other function calls above may depend on old value
  this._bEditing = bEditing;
};


/**
  *   Returns the horizontal pixel width of the edit field set by {@link DvtSvgText#setEditWidth}.
  *    @type {number} the horizontal pixel width of the edit field.
  */
DvtSvgText.prototype.getEditWidth = function(pxWidth)
{
  return this._editPxWidth ;
};


/**
  *    Defines the horizontal pixel width to contain the edit field.  This should be
  *    set before applying setEditMode(true).  If not specified,a size based on the
  *    number of characters in the DvtText is used.
  *    @param pxWidth {number} the horizontal pixel width to contain the edit field.
  */
DvtSvgText.prototype.setEditWidth = function(pxWidth)
{
  this._editPxWidth = pxWidth ;
};

DvtSvgText.prototype.setEditTooltip = function(sTip)
{
  this._editTooltip = sTip ;
};


/*
DvtSvgText.prototype.getEditBorder = function(bShow)
{
  return this._editBorder ;
};


DvtSvgText.prototype.setEditBorder = function(bShow)
{
  this._editBorder = bShow ;
  if (this._editElem)
    this._editElem.setAttribute("style", "border: " + bShow? ";" : "none;") ;
    this._editElem.setAttribute("style", "border-width: " + bShow? "1;" : "none;") ;
};
*/

/**
 * @private
 * Handle keyboard event on the HTML text area used for editing.
 * @param {KeyboardEvent} event Native keyboard event
 */
DvtSvgText.prototype._handleHtmlTextAreaKeyboardEvent = function(event) {

  //filter the event
  //TO DO: this filtering may need to happen on the native event, which is handled in DvtHtmlKeyboardListenerUtils...
  DvtSvgText._editFilter(event);
  //FIX BUG 16901294: the HTML text area will be flagged so that DvtHtmlKeyboardListenerUtils ignores its native events,
  //and we want to dispatch events from the DvtText
  this.getObj().dispatchDisplayableEvent(event.type, "" + event.keyCode);
};

DvtSvgText._editFilter = function(event)
{
   var  e    = event || window.event ;

   if (e.type == "textinput" || e.type == "textInput")
   {   //  for future filtering use
   }
   else if (e.type == "keypress")
   {
      var  code = e.charCode || e.keyCode ;
      if ( code < 32)                           // ascii ctl char?
      {
         if (code == 13) {                       // filter out CR
           if (e.preventDefault)
             e.preventDefault() ;
         }
      }
   }
};

DvtSvgText.prototype.selectEditText = function() {
  if (this._editElem) {
    this._editElem.select();
  }
};

DvtSvgText.prototype.focusEditText = function() {
  //FIX BUG 16901294: actively editing when text field receives focus
  this.SetEditing(true);
  if (this._editElem) {
    //set focus on HTML text area on timeout so that it will take precedence over any other elements that
    //may want to receive focus
    var thisRef = this;
    var func = function() {thisRef._editElem.focus();};
    window.setTimeout(func, 0);
  }
};

/**
 * @private
 * Remove focus from the HTML text area and stop editing.
 */
DvtSvgText.prototype._blurEditText = function() {
  this.SetEditing(false);
};

/**
 * @private
 * Remove the default font attributes that are set in the constructor
 * Used the font attributes in the DvtCSSStyle instead
 * @param {DvtCssStyle} style The DvtCSSStyle of this object.
 */
DvtSvgText.prototype._removeDefaultFontAttributes = function(elem)
{
  DvtSvgUtils.removeAttrNullNS(elem,"font-family");
  DvtSvgUtils.removeAttrNullNS(elem,"fill");
};


DvtSvgText.prototype._createTSpan = function(text, parentElem) {
  var tspan  = DvtSvgShapeUtils.createElement('tspan', undefined);
  if (parentElem) {
    DvtSvgUtils.appendChildElem(parentElem, tspan);
  }
  else {
    DvtSvgUtils.appendChildElem(this.getElem(), tspan);
  }

  var baseline = DvtSvgUtils.getAttrNullNS(this.getElem(), 'dominant-baseline');
  if (baseline)
      DvtSvgUtils.setAttrNullNS(tspan, "dominant-baseline",baseline);
  var anchor = DvtSvgUtils.getAttrNullNS(this.getElem(), 'text-anchor');
  if (anchor)
      DvtSvgUtils.setAttrNullNS(tspan, "text-anchor",anchor);
  
  // add text node
  if (text) {
    this._addTextNode(tspan, text);
  }
  return tspan;
};


DvtSvgText.prototype._createTextNode = function(text) {
  this._addTextNode(this.getElem(), text);
};

DvtSvgText.prototype._addTextNode = function(elem, text) {
  var textNode = document.createTextNode(text);
  if (elem) {
    DvtSvgUtils.appendChildElem(elem, textNode);
  }
  else {
    DvtSvgUtils.appendChildElem(this.getElem(), textNode);
  }
};

//Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
DvtSvgText.prototype._adjustBaseline = function(fontSize) {

  //if not in IE, no adjustment required
  var dy = 0;
  if (this._baseline != null) {
    //default fontSize to 11px
    if (! fontSize) {
      fontSize = DvtSvgUtils.getAttrNullNS(this.getElem(), 'font-size');
      if (! fontSize) {
        fontSize = DvtSvgUtils.getAttrNullNS(this.getOuterElem(), 'font-size');
        if (! fontSize)
          fontSize = "11";
      }
    }
    dy = this._baseline * parseFloat(fontSize);
    //FIX BUG 16856961: additional pixel offset for baseline, currently only
    //specified by DvtSvgTextArea subclass
    if (this._baselineOffset != null)
      dy += this._baselineOffset;
  }
  return dy;
};

DvtSvgText.prototype._setMatrix = function(mat, fontSize) {
  if (this._baseline != null && this.getObj()) {
    if (! mat) {
      mat = new DvtMatrix();
    }
    var nmat = new DvtMatrix(null, null, null, null, null, this._adjustBaseline(fontSize));
    nmat.concat(mat);
    mat = nmat;
  }
  DvtSvgText.superclass.setMatrix.call(this, mat);
}

DvtSvgText.prototype.getMatrix = function() {
  return this.getObj() ? this.getObj().getMatrix() : null;
}


/**
  *  @override
  */
DvtSvgText.prototype.setMatrix = function(mat) {
  this._setMatrix(mat, null);
}

/**
  *  @override
  */
DvtSvgText.prototype.getDimensions = function() {
  var bbox = DvtSvgText.superclass.getDimensions.call(this);
  
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  if (bbox)
    bbox.y += this._adjustBaseline(null);

  return bbox;
};

/**
 * @private
 */
DvtSvgText.prototype._createHtmlTextArea = function(obj, textElem, editText) {
   var input  = document.createElement("textArea") ;
   this._editElem = input ;
   this._editElem._obj = this;

   var bbox   = obj.getDimensions() ;
   var txt    = editText ;
   var css    = obj.getCSSStyle() ;
   var cssSize ;
   var cssFamily ;
   var cols   = 0 ;       // textArea cols

   if (! css) {
     cssSize   = DvtSvgUtils.getAttrNullNS(textElem, "font-size") || "11" ;
     cssFamily = DvtSvgUtils.getAttrNullNS(textElem, "font-family")
     css       = "font-family:" + cssFamily + ";" + " font-size: " + cssSize + "px;" ;
   }

   if (this._editPxWidth) {                            // pixel width is expected!
      // Figure out text char width to get approximate cols
      var t = new DvtText(obj.getCtx(), "W");
      t.setCSSStyle(css);
      t.alignMiddle();
      obj.getParent().addChild(t);
      var dims = t.getDimensions();
      obj.getParent().removeChild(t);
      cols = (this._editPxWidth/dims.w) ;
   }
   else {                                              // no pixel width!
      if (bbox.w == 0) {                               // just use some default value so
        bbox.w = 10 ;                                  // that its at least visible.
      }
      this._editPxWidth = bbox.w * 2 ;
      cols = 2 ;
   }

   cols = Math.floor(cols * 1.5) ;                       // heuristic for cols
   //console.log("cols=" + cols) ;
   
   input.setAttribute("rows", "1") ;
   input.setAttribute("cols",  cols) ;           // cols determines edit box width
   if (txt) {
     input.value = txt ;
   }
   else {
     input.value = "";
   }

   if (this._editTooltip) {
     input.setAttribute("title", this._editTooltip) ;
   }

   css += " color:" + DvtSvgUtils.getAttrNullNS(textElem, "fill") + ";" ;
   css += " overflow-x: hidden;" ;      
   css += " border: none; border-width: 0px; margin: 0px; resize: none; outline: none;" ; 
   css += " dominant-baseline:" + DvtSvgUtils.getAttrNullNS(textElem, "dominant-baseline") + ";" ;

// css += " line-height: 1;" ; 
   
   //FIX BUG 16901294: absolutely position the HTML text area over the DvtText
   var localPoint = new DvtPoint(this.getX(), this.getY());
   var stagePoint = this.getObj().localToStage(localPoint);
   css += " position: absolute; top: " + stagePoint.y + "px; left: " + stagePoint.x + "px;" ;
   
   css += " vertical-align: baseline; outline-offset: 0px;" ; 
   var padding = 2;
   if (DvtAgent.isRightToLeft(this.getObj().getCtx())) {
     css += " text-align: right; padding: 0px " + padding + "px 0px 0px;" ;
   }
   else {
     css += " text-align: left; padding: 0px 0px 0px " + padding + "px;" ;
   }
   
   input.setAttribute("style", css) ;

   if (DvtAgent.isBrowserChrome() || DvtAgent.isBrowserSafari()) {
     input.setAttribute("wrap", "off") ;
   }
   
   //FIX BUG 16901294: mark the HTML text area so that DvtHtmlKeyboardListenerUtils will ignore its native events,
   //because the div that DvtHtmlKeyboardListenerUtils listens on will also get the text area events
   input[DvtHtmlKeyboardListenerUtils.ATTR_IGNORE_EVENTS_FROM_TARGET] = true;

   return input ;
} ;

DvtSvgText.prototype.AddElemListener = function(type, listener, useCapture) {
  if (this.getEditMode() && this._editElem) {
    DvtSvgUtils.addDomEventListener(this._editElem, type, listener, useCapture);
    if (type == DvtTouchEvent.TOUCHEND) {
        DvtSvgUtils.addDomEventListener(this._editElem, DvtTouchEvent.TOUCHCANCEL, listener, useCapture);
    }
  }
  
  DvtSvgText.superclass.AddElemListener.call(this, type, listener, useCapture);
};

//FIX BUG 16901294: when editing, getElem() will not return the text element, so provide a function
//that will always do that
/**
 * @protected
 * Get the text DOM element.
 */
DvtSvgText.prototype.GetTextElem = function() {
  return this._elem;
};

/**
 * Removes existing textarea from the DOM including listeners attached to it
 */
DvtSvgText.prototype.destroy = function() {
  if (this._editElem) {
    this.SetEditing(false);  
    this._editElem = null;
  }
};

/**
 * Returns true if the text anchor needs to be flipped from "start" to "end" and vice versa.
 * @param {DvtContext} context
 * @return {boolean}
 */
DvtSvgText.needsTextAnchorAdjustment = function(context) {
  // Bug 17776065: When html dir="rtl", Webkit and FF25+ treat the right side of the text as the start, and the left 
  // side of the text as end.  Our API always treats the left side as start, so we need to adjust based on agent.
  // Note: Technically this context check is not correct, because the text anchor adjustment is not based on the reading
  // direction of our context, but rather the rtl flag on the page.  We are passing context incorrectly here so that our
  // unit tests can be used to verify rtl support for JET components, and we should remove this context param once all
  // components have been updated to support rtl in JET (by passing context within their RTL calls).  We'd do this by
  // setting documentElement.document.dir to rtl in the test environment, which mimics the situation where the adjustment
  // is needed in the browser.
  return DvtAgent.isRightToLeft(context) &&  
         (DvtAgent.isPlatformWebkit() || (DvtAgent.isPlatformGecko() && DvtAgent.getVersion() >= 25));
}
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.
/*-------------------------------------------------------------------------*/
/*   DvtSvgTextArea        SVG implementation of textArea "shape"          */
/*-------------------------------------------------------------------------*/
/**
 * @constructor
 * Creates an instance of DvtSvgTextArea.
 * @param {DvtContext} context
 * @extends DvtSvgShape
 * @class DvtSvgTextArea
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 */
var DvtSvgTextArea = function(context, x, y, id) {
  this._Init(context, x, y, id) ;
};

DvtObj.createSubclass(DvtSvgTextArea, DvtSvgText, "DvtSvgTextArea") ;


/**
 * Initializes this instance of DvtTextArea.
 * @param {DvtContext} context
 * @param text {string} the text string
 * @param x {number} x the x position
 * @param y {number} y the y position
 * @param id {string} the id for this object
 */
DvtSvgTextArea.prototype._Init = function(context, x, y, id) {
  //remove this if graph is ok with the text alignment changes
  if (x === undefined && y === undefined) {
    x = 0;
    y = 0;
    this._notGraph = true;
  }

  DvtSvgTextArea.superclass._Init.call(this, context, "", x, y, id) ;  
  
  // the adjustment to the amount of space between lines
  this._leading = 0;
}


/**
 * Sets the text string for this textArea object.
 * @param {array} single line text or multiline text
 * @param {array} dimList Optional dimensions of multilines
 */
DvtSvgTextArea.prototype.setText = function(multilines, dimList) {
  var singleLine;
  if (DvtArrayUtils.isArray(multilines)) {
    if (multilines.length == 1)
      singleLine = multilines[0];
  }
  else {
    singleLine = multilines;
  }

  // clear the old text
  var obj = this.getObj();
  var elem = this.getElem();

  // keep the old dominant-baseline
  var dbl = this._getCurrentDominantBaseline();

  var child = elem.firstChild;
  while(child != null) {
    var delNode = child;
    child = child.nextSibling;
    elem.removeChild(delNode);
  }
  
  //FIX BUG 16856961: save multiline dimensions for vertical alignment
  this._multilineDims = null;

  if (obj.getNumChildren() === 0 && singleLine) {
    // Update the text node if it is already created
    var textNode = this.getElem().firstChild;
    if(textNode) {
      textNode.nodeValue = singleLine;
    }
    // Otherwise create it
    else {
      this._addTextLine(obj, singleLine);
    }
  }
  else {
    var oldx = parseFloat(DvtSvgUtils.getAttrNullNS(elem, 'x'));
    var oldy = parseFloat(DvtSvgUtils.getAttrNullNS(elem, 'y'));
    if (isNaN(oldx)) {
      // FIX Bug 16588881 - js chart: pie labels may overflow when the pie is small
      // Problem with multiline labels resolved by following check
      oldx = 0;
    }
    if (isNaN(oldy)) {
      oldy = 0;
    }
    if (singleLine) {
      this._addLine(obj, singleLine, oldx, oldy);
    }
    else {
      var x = 0;
      //line position needs to start at specified value
      var y = oldy;
      var dim;
      var maxDim = new DvtRectangle(oldx, oldy, obj._getMaxTextWidth(), obj._getMaxTextHeight());

      //FIX BUG 16856961: save the multiline dimensions for vertical alignment
      this._multilineDims = [];
      for (var i = 0; i < multilines.length; i++) {
        dim = (dimList && dimList[i]) ? dimList[i] : maxDim;
        this._multilineDims.push(dim);

        x = oldx;
        if (this._notGraph) 
          x += this._getHorzOffset(dim.w);

        this._addTextLine(obj, multilines[i], x, y, dbl);

        y += dim.h;
      }

      //Bug 13542241 - treemap node content sometimes doesn't respect bold
      var g = this.getOuterElem();
      if (g.nodeName && g.nodeName == "g" && g !== elem) {
        //remove the old element
        g.removeChild(elem);

        //apply css styles on the group element
        var style = this.getCSSStyle();
        if (style) {
          this.setCSSStyle(style);
        }
      }
    }
  }
  
  //FIX BUG 16856961: refresh vertical alignment
  this.RefreshVertAlign();
}


/**
 * Gets the text string for this textArea object.
 * @param {string} text the text string
 */
DvtSvgTextArea.prototype.getText = function() {
  var obj = this.getObj();
  var nkids = obj.getNumChildren();

  if (nkids == 0) {
    return DvtSvgTextArea.superclass.getText.call(this);
  }
  else {
    var child;
    var text = "";
    for (var i = 0; i < nkids; i++) {
      child = obj.getChildAt(i);
      text += child.getText();
    }
  }
  return text;
}


/**
 * Returns the amount of vertical space, in pixels, between lines
 * @return {number} the amount of vertical space (called leading) between lines
 */
DvtSvgTextArea.prototype.getLeading = function() {
  return this._leading;
};

/**
 * Sets the amount of vertical space, in pixels, between lines
 * @param {number} leading amount of vertical space, in pixels, between lines
 */
DvtSvgTextArea.prototype.setLeading = function(leading) {
  this._leading = leading;
};

// add a text line
DvtSvgTextArea.prototype._addLine = function(obj, newLineText, x, dy) {
  var newText = this._createTSpan(newLineText);
  DvtSvgUtils.setAttrNullNS(newText, 'x', x);
  DvtSvgUtils.setAttrNullNS(newText, 'dy', dy + this.getLeading());

  // peformance: dont getDimensions for each line
//   return this.getDimensions().h;
}

// add a text line
DvtSvgTextArea.prototype._addTextLine = function(obj, newLineText, x, y, dbl) {
  var newDvtText = new DvtText(obj.getCtx(), newLineText, x, y, null);
  newDvtText.setParent(obj);
  
  var newText = newDvtText.getImpl();
  var textNode = this.getElem().firstChild;
  
  if (textNode == null){
      textNode = this.getElem();
  }
  var attr = DvtSvgUtils.getAttrNullNS(textNode, 'dominant-baseline');
  if (attr) {
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "dominant-baseline",attr);
  }
  else if (dbl) {
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "dominant-baseline",dbl);
  }

  attr = DvtSvgUtils.getAttrNullNS(textNode, 'text-anchor');
  if (attr)
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "text-anchor",attr);
      
  attr = DvtSvgUtils.getAttrNullNS(textNode, 'font-family');
  if (attr)
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "font-family",attr);
      
  attr = DvtSvgUtils.getAttrNullNS(textNode, 'font-size');
  if (attr)
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "font-size",attr);
      
  attr = DvtSvgUtils.getAttrNullNS(textNode, 'fill');
  if (attr)
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "fill",attr);
      
  attr = DvtSvgUtils.getAttrNullNS(textNode, 'cursor');
  if (attr)
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "cursor",attr);

  // Note: This code doesn't get called in anything except FF v24, and it's unclear whether it's useful or not.  Once FF24 is removed,
  // we should just get rid of it.  Fake usage to help search:
  // DvtAgent.isPlatformGecko() && DvtAgent.getVersion() < 25;
  if (DvtAgent.isRightToLeft(obj.getCtx())) {
    attr = DvtSvgUtils.getAttrNullNS(textNode, 'unicode-bidi');
    if (attr)
      DvtSvgUtils.setAttrNullNS(newText.getElem(), "unicode-bidi", attr);
  }
  
  //FIX BUG 16856961: remove vertical alignment transform on child text so it
  //doesn't interfere with vert align transform on this text area
  if (DvtAgent.isPlatformIE()){
    DvtSvgUtils.setAttrNullNS(newText.getElem(), "transform", null);
    DvtSvgUtils.removeAttrNullNS(newText.getElem(), "transform");
  }
  
  this.addChild(newText);
}


DvtSvgTextArea.prototype._getTextAlign = function() {
  var style = this.getCSSStyle();
  var textAlign = style["text-align"];
  switch (textAlign) {
  case "start":
  case "end":
  case "center":
    break;

  case "right":
    textAlign = "end";
    break;

  case "left":
    textAlign = "start";
    break;

  default:
    textAlign = DvtAgent.isRightToLeft(this.getObj().getCtx())? "end" : "start";
    break;
  }

  return textAlign;
}


/**
 * @override
 */
DvtSvgTextArea.prototype.setCursor = function (cursorType) {
  DvtSvgTextArea.superclass.setCursor.call(this, cursorType);

  var elem = this.getElem();
  if (elem != null) {
    for (var i = 0;i < elem.childElementCount;i++) {
      var child = elem.childNodes[i];
      DvtSvgUtils.setAttrNullNS(child, "cursor", cursorType);
    }
  }
}


DvtSvgTextArea.prototype._getHorzOffset = function(ww) {
  var offset = 0;
  var obj = this.getObj();
  var textAlign = this._getTextAlign();
  
  if (textAlign == "end") {
    offset = obj._getMaxTextWidth() - ww;
  }
  else if (textAlign == "center") {
    offset = (obj._getMaxTextWidth() - ww) / 2;
  }
  
  // Bug 17776065: When html dir="rtl", Webkit and FF25+ treat the right side of the start as the start, and the left 
  // side of the text as end.  Our API always treats the left side as start, so we need to adjust based on agent.
  var bAdjust = DvtSvgText.needsTextAnchorAdjustment(obj.getCtx());
  if (bAdjust) {
    offset += ww;
  }

  return offset;
}

//FIX BUG 16856961:
/**
 * @protected
 * Refresh vertical alignment when text changes.
 */
DvtSvgTextArea.prototype.RefreshVertAlign = function() {
  //Bug 13879007 - NODE RENDERED INCORRECTLY IN IE9
  if (DvtAgent.isPlatformIE()){
    this.SetBaseline(this._baseline);
  }
  else {
    this._adjustMultiBaselines();
  }
}

//FIX BUG 16856961:
/**
 * @override
 */
DvtSvgTextArea.prototype.SetBaseline = function(baseline) {
  //if there are multiple lines, calculate an additional pixel baseline offset
  this._baselineOffset = null;
  if (this._multilineDims) {
    var accumHeight = 0;
    //the first line is already shifted correctly for a single line, so only
    //need to take additional lines into account to determine extra shift
    for (var j = 1; j < this._multilineDims.length; j++) {
      accumHeight += this._multilineDims[j].h;
    }
    switch (this.getObj().getVertAlignment()) {
      case DvtText.V_ALIGN_MIDDLE:
        this._baselineOffset = -.5 * accumHeight;
        break;
      case DvtText.V_ALIGN_BOTTOM:
      case DvtText.V_ALIGN_BASELINE:
        this._baselineOffset = -accumHeight;
        break;
    }
  }
  DvtSvgTextArea.superclass.SetBaseline.call(this, baseline);
}

/**
 * @override
 * Set the dominant baseline for vertical alignment.
 */
DvtSvgTextArea.prototype.SetDominantBaselineAttr = function(baseline) {
  DvtSvgTextArea.superclass.SetDominantBaselineAttr.call(this, baseline);
  
  //FIX BUG 16856961: adjust baselines for vertical alignment
  this._adjustMultiBaselines();
}

/**
 * @private
 * Get the current value of dominant-baseline.
 */
DvtSvgTextArea.prototype._getCurrentDominantBaseline = function() {
  var elem = this.getElem();
  var dbl;
  if (elem && elem.nodeName == "g") {
    var childNodes = elem.childNodes;
    if (childNodes && childNodes.length > 0 && childNodes[0].nodeName == "text") {
      dbl = DvtSvgUtils.getAttrNullNS(childNodes[0], 'dominant-baseline');
    }
  }
  return dbl;
}

//FIX BUG 16856961: 
/**
 * @private
 * Adjust baselines for vertical alignment of multi-line text.
 */
DvtSvgTextArea.prototype._adjustMultiBaselines = function() {
  var elem = this.getElem();
  if (elem && this._multilineDims) {
    var valign = this.getObj().getVertAlignment();
    var baselineShiftAttr = "baseline-shift";
    var dominantBaselineAttr = "dominant-baseline";
    var dominantBaselineValue = this._getCurrentDominantBaseline();
    var px = "px";
    var numChildren = elem.childElementCount;
    var accumHeight = 0;
    
    //the first line is already shifted correctly for a single line, so only
    //need to take additional lines into account to determine extra shift
    for (var j = 1; j < this._multilineDims.length; j++) {
      accumHeight += this._multilineDims[j].h;
    }
    
    for (var i = 0; i < numChildren; i++) {
      var child = elem.childNodes[i];
      
      //copy the dominant-baseline from first line to other lines
      if (dominantBaselineValue) {
        DvtSvgUtils.setAttrNullNS(child, dominantBaselineAttr, dominantBaselineValue);
      }
      else {
        DvtSvgUtils.removeAttrNullNS(child, dominantBaselineAttr);
      }
      
      //shift the baseline
      switch (valign) {
        case DvtText.V_ALIGN_TOP:
          DvtSvgUtils.removeAttrNullNS(child, baselineShiftAttr);
          break;
        case DvtText.V_ALIGN_MIDDLE:
          DvtSvgUtils.setAttrNullNS(child, baselineShiftAttr, (.5 * accumHeight) + px);
          break;
        case DvtText.V_ALIGN_BOTTOM:
        case DvtText.V_ALIGN_BASELINE:
          DvtSvgUtils.setAttrNullNS(child, baselineShiftAttr, accumHeight + px);
          break;
      }
    }
  }
}
// Copyright (c) 2011, 2023, Oracle and/or its affiliates.

/**
 * Creates an instance of DvtSvgTextFormatted.
 * @param {DvtContext} context
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 * @constructor
 * @extends DvtSvgShape
 * @class DvtSvgTextFormatted
 */
var DvtSvgTextFormatted = function(context, x, y, id) {
  this._Init(context, x, y, id) ;
};

DvtObj.createSubclass(DvtSvgTextFormatted, DvtSvgText, "DvtSvgTextFormatted") ;


DvtSvgTextFormatted.BOLD = "b";
DvtSvgTextFormatted.BREAK = "br";
DvtSvgTextFormatted.ITALIC = "i";
DvtSvgTextFormatted.LIST_ITEM = "li";
DvtSvgTextFormatted.ORDERED_LIST = "ol";
DvtSvgTextFormatted.PARAGRAPH = "p";
DvtSvgTextFormatted.UNORDERED_LIST = "ul";


/**
 * Initializes this instance of DvtTextFormatted.
 * @param {DvtContext} context
 * @param text {string} the text string
 * @param x {number} x the x position
 * @param y {number} y the y position
 * @param id {string} the id for this object
 */
DvtSvgTextFormatted.prototype._Init = function(context, x, y, id) {
  DvtSvgTextFormatted.superclass._Init.call(this, context, "", x, y, id) ;
};


/**
 * Sets the text string for this textArea object.
 * @param {array} single line text or multiline text
 */
DvtSvgTextFormatted.prototype.setText = function(text) {
  // parse the formatted text
  var obj = this.getObj();
  var parser = new DvtXmlParser(obj.getCtx());

  // wrap around the text with a tag to make the dom parser happy
  var newText = "<root>" + text + "</root>";
  var node = parser.parse(newText);

  if (node) {
    //disable vertical indentation until something is rendered, so
    //that we don't render empty lines at the top
    this._bEnableVertIndent = false;
    this._parseChildren(node, null, 0, false, false);
  }

};

DvtSvgTextFormatted.prototype._parseChildren = function(node, currTspan, nestedListLevel, bFirstListItem, bListItem) {
  var childNodes = node.getAllChildNodes();
  var childCnt = childNodes.length;

  var bPrevP = false;
  for (var i = 0; i < childCnt; i++) {
    var child = childNodes[i];
    if (child) {
      var childName = child.getName();
      
      //if <p>, then need to shift all subsequent siblings
      //by additional amount at end of paragraph
      if (bPrevP && 
          childName !== DvtSvgTextFormatted.PARAGRAPH &&
          childName !== DvtSvgTextFormatted.ORDERED_LIST &&
          childName !== DvtSvgTextFormatted.UNORDERED_LIST) {
        var pTspan = this._handleMarkup(DvtSvgTextFormatted.PARAGRAPH, currTspan);
        currTspan = pTspan;
      }
      bPrevP = false;
      
      // text node
      if (childName === '#text') {
        var strText = child.getNodeValue();
        if (bListItem) {
          strText = "- " + strText;
        }
        this._addTextNode(currTspan, strText);
        //enable vertical indentation now that we've rendered something
        this._bEnableVertIndent = true;
      }
      // element
      else {
        var tspan = this._handleMarkup(childName, currTspan, nestedListLevel, bFirstListItem);
        
        var childNestedListLevel = nestedListLevel;
        var childBFirstListItem = false;
        if (childName === DvtSvgTextFormatted.ORDERED_LIST ||
            childName === DvtSvgTextFormatted.UNORDERED_LIST) {
          if (childNestedListLevel == 0) {
            childBFirstListItem = true;
          }
          childNestedListLevel++;
        }
        
        this._parseChildren(child, tspan, childNestedListLevel, childBFirstListItem, (childName === DvtSvgTextFormatted.LIST_ITEM));
        
        //if <br>, then need to shift all subsequent siblings
        if (childName === DvtSvgTextFormatted.BREAK) {
          currTspan = tspan;
        }
        //if <p>, then need to shift all subsequent siblings
        //by additional amount at end of paragraph
        if (childName === DvtSvgTextFormatted.PARAGRAPH ||
            ((childName === DvtSvgTextFormatted.ORDERED_LIST ||
              childName === DvtSvgTextFormatted.UNORDERED_LIST) &&
             nestedListLevel < 1)) {
          bPrevP = true;
        }
        //if processed the first <li>, then toggle the flag to false
        if (childName === DvtSvgTextFormatted.LIST_ITEM) {
          bFirstListItem = false;
        }
      }
    } //end if (child)
  } //end for (var i = 0; i < childCnt; i++)
};


// handle html markup
DvtSvgTextFormatted.prototype._handleMarkup = function(nodeName, currTspan, nestedListLevel, bFirstListItem) {
  // create tspan
  var tspan  = this._createTSpan(null, currTspan);

  // element
  if (nodeName === DvtSvgTextFormatted.BOLD) {
    DvtSvgUtils.setAttrNullNS(tspan, 'font-weight', 'bold');
  }
  else if (nodeName === DvtSvgTextFormatted.ITALIC) {
    DvtSvgUtils.setAttrNullNS(tspan, 'font-style', 'italic');
  }
  else if (nodeName === DvtSvgTextFormatted.BREAK) {
    DvtSvgUtils.setAttrNullNS(tspan, 'x', '0');
    DvtSvgUtils.setAttrNullNS(tspan, 'dy', '1em');
  }
  else if (nodeName === DvtSvgTextFormatted.PARAGRAPH) {
    if (this._bEnableVertIndent) {
      DvtSvgUtils.setAttrNullNS(tspan, 'x', '0');
      DvtSvgUtils.setAttrNullNS(tspan, 'dy', '2em');
    }
    //enable vertical indentation now that we've rendered something
    this._bEnableVertIndent = true;
  }
  else if (nodeName === DvtSvgTextFormatted.ORDERED_LIST ||
           nodeName === DvtSvgTextFormatted.UNORDERED_LIST) {
  }
  else if (nodeName === DvtSvgTextFormatted.LIST_ITEM) {
    DvtSvgUtils.setAttrNullNS(tspan, 'x', (nestedListLevel) +'em');
    if (this._bEnableVertIndent) {
      if (bFirstListItem) {
        DvtSvgUtils.setAttrNullNS(tspan, 'dy', '2em');
      }
      else {
        DvtSvgUtils.setAttrNullNS(tspan, 'dy', '1em');
      }
    }
    //enable vertical indentation now that we've rendered something
    this._bEnableVertIndent = true;
  }
//     DvtSvgUtils.setAttrNullNS(tspan, 'text-decoration', 'underline');
  
  return tspan;
};


