function drawRenderLayer (ctx, layer) {
  var customDrawFunc;

  // Performance: avoid drawing hidden layers.
  if (typeof layer.alpha === 'number' && layer.alpha <= 0) {
    return;
  }

  switch (layer.type) {
    case 'image':
      customDrawFunc = drawImageRenderLayer;
      break;

    case 'text':
      customDrawFunc = drawTextRenderLayer;
      break;

    case 'gradient':
      customDrawFunc = drawGradientRenderLayer;
      break;
  }

  // Establish drawing context for certain properties:
  // - alpha
  // - translate
  var saveContext = (layer.alpha !== null && layer.alpha < 1) ||
                    (layer.translateX || layer.translateY);

  if (saveContext) {
    ctx.save();

    // Alpha:
    if (layer.alpha !== null && layer.alpha < 1) {
      ctx.globalAlpha = layer.alpha;
    }

    // Translation:
    if (layer.translateX || layer.translateY) {
      ctx.translate(layer.translateX || 0, layer.translateY || 0);
    }
  }

  // If the layer is bitmap-cacheable, draw in a pooled off-screen canvas.
  // We disable backing stores on pad since we flip there.
  if (layer.backingStoreId) {
    drawCacheableRenderLayer(ctx, layer, customDrawFunc);
  } else {
    // Draw default properties, such as background color.
    ctx.save();
    drawBaseRenderLayer(ctx, layer);

    // Draw custom properties if needed.
    customDrawFunc && customDrawFunc(ctx, layer);
    ctx.restore();

    // Draw child layers, sorted by their z-index.
    if (layer.children) {
      layer.children.slice().sort(sortByZIndexAscending).forEach(function (childLayer) {
        drawRenderLayer(ctx, childLayer);
      });
    }
  }

  // Pop the context state if we established a new drawing context.
  if (saveContext) {
    ctx.restore();
  }
}
Draw a RenderLayer instance to a <canvas> context.

@param {CanvasRenderingContext2d} ctx
@param {RenderLayer} layer