Esempio n. 1
0
FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags)
{
    Filter* filter = this->filter();
    ASSERT(filter);

    // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect.
    FloatRect subregion;
    if (unsigned numberOfInputEffects = inputEffects().size()) {
        subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags);
        for (unsigned i = 1; i < numberOfInputEffects; ++i)
            subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(flags));
    } else {
        subregion = filter->filterRegion();
    }

    // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>.
    if (filterEffectType() == FilterEffectTypeTile)
        subregion = filter->filterRegion();

    if (flags & MapRectForward) {
        // mapRect works on absolute rectangles.
        subregion = filter->mapAbsoluteRectToLocalRect(mapRect(
            filter->mapLocalRectToAbsoluteRect(subregion)));
    }

    FloatRect boundaries = effectBoundaries();
    if (hasX())
        subregion.setX(boundaries.x());
    if (hasY())
        subregion.setY(boundaries.y());
    if (hasWidth())
        subregion.setWidth(boundaries.width());
    if (hasHeight())
        subregion.setHeight(boundaries.height());

    setFilterPrimitiveSubregion(subregion);

    FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);

    // Clip every filter effect to the filter region.
    if (flags & ClipToFilterRegion) {
        absoluteSubregion.intersect(filter->absoluteFilterRegion());
    }

    setMaxEffectRect(absoluteSubregion);
    return subregion;
}
Esempio n. 2
0
void FETile::apply()
{
// FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise.
#if ENABLE(SVG)
    FilterEffect* in = inputEffect(0);
    in->apply();
    if (!in->resultImage())
        return;

    GraphicsContext* filterContext = effectContext();
    if (!filterContext)
        return;

    setIsAlphaImage(in->isAlphaImage());

    // Source input needs more attention. It has the size of the filterRegion but gives the
    // size of the cutted sourceImage back. This is part of the specification and optimization.
    FloatRect tileRect = in->maxEffectRect();
    FloatPoint inMaxEffectLocation = tileRect.location();
    FloatPoint maxEffectLocation = maxEffectRect().location();
    if (in->filterEffectType() == FilterEffectTypeSourceInput) {
        Filter* filter = this->filter();
        tileRect = filter->filterRegion();
        tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height());
    }

    OwnPtr<ImageBuffer> tileImage;
    if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB))
        return;

    GraphicsContext* tileImageContext = tileImage->context();
    tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y());
    tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location());

    RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true);

    AffineTransform patternTransform;
    patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y());
    pattern->setPatternSpaceTransform(patternTransform);
    filterContext->setFillPattern(pattern);
    filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()));
#endif
}
Esempio n. 3
0
GraphicsContext* SVGFilterPainter::prepareEffect(
    const LayoutObject& object,
    SVGFilterRecordingContext& recordingContext) {
  m_filter.clearInvalidationMask();

  if (FilterData* filterData = m_filter.getFilterDataForLayoutObject(&object)) {
    // If the filterData already exists we do not need to record the content
    // to be filtered. This can occur if the content was previously recorded
    // or we are in a cycle.
    if (filterData->m_state == FilterData::PaintingFilter)
      filterData->m_state = FilterData::PaintingFilterCycleDetected;

    if (filterData->m_state == FilterData::RecordingContent)
      filterData->m_state = FilterData::RecordingContentCycleDetected;

    return nullptr;
  }

  SVGFilterGraphNodeMap* nodeMap = SVGFilterGraphNodeMap::create();
  FilterEffectBuilder builder(nullptr, object.objectBoundingBox(), 1);
  Filter* filter = builder.buildReferenceFilter(
      toSVGFilterElement(*m_filter.element()), nullptr, nodeMap);
  if (!filter || !filter->lastEffect())
    return nullptr;

  IntRect sourceRegion = enclosingIntRect(
      intersection(filter->filterRegion(), object.strokeBoundingBox()));
  filter->getSourceGraphic()->setSourceRect(sourceRegion);

  FilterData* filterData = FilterData::create();
  filterData->lastEffect = filter->lastEffect();
  filterData->nodeMap = nodeMap;

  // TODO(pdr): Can this be moved out of painter?
  m_filter.setFilterDataForLayoutObject(const_cast<LayoutObject*>(&object),
                                        filterData);
  return recordingContext.beginContent(filterData);
}
Esempio n. 4
0
void SVGFilterRecordingContext::endContent(FilterData* filterData) {
  DCHECK_EQ(filterData->m_state, FilterData::RecordingContent);

  Filter* filter = filterData->lastEffect->getFilter();
  SourceGraphic* sourceGraphic = filter->getSourceGraphic();
  DCHECK(sourceGraphic);

  // Use the context that contains the filtered content.
  DCHECK(m_paintController);
  DCHECK(m_context);
  m_context->beginRecording(filter->filterRegion());
  m_paintController->commitNewDisplayItems();
  m_paintController->paintArtifact().replay(*m_context);

  SkiaImageFilterBuilder::buildSourceGraphic(sourceGraphic,
                                             m_context->endRecording());

  // Content is cached by the source graphic so temporaries can be freed.
  m_paintController = nullptr;
  m_context = nullptr;

  filterData->m_state = FilterData::ReadyToPaint;
}