docs: function (color, elem, prop, wrapper) {
                  var renderer = this,
                    colorObject,
                    regexRgba = /^rgba/,
                    markup,
                    fillType,
                    ret = NONE;
  
                  // Check for linear or radial gradient
                  if (color && color.linearGradient) {
                      fillType = 'gradient';
                  } else if (color && color.radialGradient) {
                      fillType = 'pattern';
                  }
  
  
                  if (fillType) {
  
                      var stopColor,
                        stopOpacity,
                        gradient = color.linearGradient || color.radialGradient,
                        x1,
                        y1,
                        x2,
                        y2,
                        opacity1,
                        opacity2,
                        color1,
                        color2,
                        fillAttr = '',
                        stops = color.stops,
                        firstStop,
                        lastStop,
                        colors = [],
                        addFillNode = function () {
                            // Add the fill subnode. When colors attribute is used, the meanings of opacity and o:opacity2
                            // are reversed.
                            markup = ['<fill colors="' + colors.join(',') + '" opacity="', opacity2, '" o:opacity2="', opacity1,
                                '" type="', fillType, '" ', fillAttr, 'focus="100%" method="any" />'];
                            createElement(renderer.prepVML(markup), null, null, elem);
                        };
  
                      // Extend from 0 to 1
                      firstStop = stops[0];
                      lastStop = stops[stops.length - 1];
                      if (firstStop[0] > 0) {
                          stops.unshift([
                              0,
                              firstStop[1]
                          ]);
                      }
                      if (lastStop[0] < 1) {
                          stops.push([
                              1,
                              lastStop[1]
                          ]);
                      }
  
                      // Compute the stops
                      each(stops, function (stop, i) {
                          if (regexRgba.test(stop[1])) {
                              colorObject = Color(stop[1]);
                              stopColor = colorObject.get('rgb');
                              stopOpacity = colorObject.get('a');
                          } else {
                              stopColor = stop[1];
                              stopOpacity = 1;
                          }
  
                          // Build the color attribute
                          colors.push((stop[0] * 100) + '% ' + stopColor);
  
                          // Only start and end opacities are allowed, so we use the first and the last
                          if (!i) {
                              opacity1 = stopOpacity;
                              color2 = stopColor;
                          } else {
                              opacity2 = stopOpacity;
                              color1 = stopColor;
                          }
                      });
  
                      // Apply the gradient to fills only.
                      if (prop === 'fill') {
  
                          // Handle linear gradient angle
                          if (fillType === 'gradient') {
                              x1 = gradient.x1 || gradient[0] || 0;
                              y1 = gradient.y1 || gradient[1] || 0;
                              x2 = gradient.x2 || gradient[2] || 0;
                              y2 = gradient.y2 || gradient[3] || 0;
                              fillAttr = 'angle="' + (90  - math.atan(
                                  (y2 - y1) / // y vector
                                  (x2 - x1) // x vector
                                ) * 180 / mathPI) + '"';
  
                              addFillNode();
  
                              // Radial (circular) gradient
                          } else {
  
                              var r = gradient.r,
                                sizex = r * 2,
                                sizey = r * 2,
                                cx = gradient.cx,
                                cy = gradient.cy,
                                radialReference = elem.radialReference,
                                bBox,
                                applyRadialGradient = function () {
                                    if (radialReference) {
                                        bBox = wrapper.getBBox();
                                        cx += (radialReference[0] - bBox.x) / bBox.width - 0.5;
                                        cy += (radialReference[1] - bBox.y) / bBox.height - 0.5;
                                        sizex *= radialReference[2] / bBox.width;
                                        sizey *= radialReference[2] / bBox.height;
                                    }
                                    fillAttr = 'src="' + defaultOptions.global.VMLRadialGradientURL + '" ' +
                                      'size="' + sizex + ',' + sizey + '" ' +
                                      'origin="0.5,0.5" ' +
                                      'position="' + cx + ',' + cy + '" ' +
                                      'color2="' + color2 + '" ';
  
                                    addFillNode();
                                };
  
                              // Apply radial gradient
                              if (wrapper.added) {
                                  applyRadialGradient();
                              } else {
                                  // We need to know the bounding box to get the size and position right
                                  wrapper.onAdd = applyRadialGradient;
                              }
  
                              // The fill element's color attribute is broken in IE8 standards mode, so we
                              // need to set the parent shape's fillcolor attribute instead.
                              ret = color1;
                          }
  
                          // Gradients are not supported for VML stroke, return the first color. #722.
                      } else {
                          ret = stopColor;
                      }
  
                      // if the color is an rgba color, split it and add a fill node
                      // to hold the opacity component
                  } else if (regexRgba.test(color) && elem.tagName !== 'IMG') {
  
                      colorObject = Color(color);
  
                      markup = ['<', prop, ' opacity="', colorObject.get('a'), '"/>'];
                      createElement(this.prepVML(markup), null, null, elem);
  
                      ret = colorObject.get('rgb');
  
  
                  } else {
                      var propNodes = elem.getElementsByTagName(prop); // 'stroke' or 'fill' node
                      if (propNodes.length) {
                          propNodes[0].opacity = 1;
                          propNodes[0].type = 'solid';
                      }
                      ret = color;
                  }
  
                  return ret;
              }