Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: Source/core/platform/graphics/filters/FilterEffect.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
3 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5 * Copyright (C) 2012 University of Szeged
6 * Copyright (C) 2013 Google Inc. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25
26 #include "core/platform/graphics/filters/FilterEffect.h"
27
28 #include "core/platform/graphics/ImageBuffer.h"
29 #include "core/platform/graphics/filters/Filter.h"
30
31 #if HAVE(ARM_NEON_INTRINSICS)
32 #include <arm_neon.h>
33 #endif
34
35 namespace WebCore {
36
37 FilterEffect::FilterEffect(Filter* filter)
38 : m_alphaImage(false)
39 , m_filter(filter)
40 , m_hasX(false)
41 , m_hasY(false)
42 , m_hasWidth(false)
43 , m_hasHeight(false)
44 , m_clipsToBounds(true)
45 , m_operatingColorSpace(ColorSpaceLinearRGB)
46 , m_resultColorSpace(ColorSpaceDeviceRGB)
47 {
48 ASSERT(m_filter);
49 }
50
51 FilterEffect::~FilterEffect()
52 {
53 }
54
55 inline bool isFilterSizeValid(IntRect rect)
56 {
57 if (rect.width() < 0 || rect.width() > kMaxFilterSize
58 || rect.height() < 0 || rect.height() > kMaxFilterSize)
59 return false;
60 return true;
61 }
62
63 void FilterEffect::determineAbsolutePaintRect()
64 {
65 m_absolutePaintRect = IntRect();
66 unsigned size = m_inputEffects.size();
67 for (unsigned i = 0; i < size; ++i)
68 m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
69
70 // Filters in SVG clip to primitive subregion, while CSS doesn't.
71 if (m_clipsToBounds)
72 m_absolutePaintRect.intersect(enclosingIntRect(m_maxEffectRect));
73 else
74 m_absolutePaintRect.unite(enclosingIntRect(m_maxEffectRect));
75
76 }
77
78 FloatRect FilterEffect::mapRectRecursive(const FloatRect& rect)
79 {
80 FloatRect result;
81 if (m_inputEffects.size() > 0) {
82 result = m_inputEffects.at(0)->mapRectRecursive(rect);
83 for (unsigned i = 1; i < m_inputEffects.size(); ++i)
84 result.unite(m_inputEffects.at(i)->mapRectRecursive(rect));
85 } else
86 result = rect;
87 return mapRect(result);
88 }
89
90 FloatRect FilterEffect::getSourceRect(const FloatRect& destRect, const FloatRect & destClipRect)
91 {
92 FloatRect sourceRect = mapRect(destRect, false);
93 FloatRect sourceClipRect = mapRect(destClipRect, false);
94
95 FloatRect boundaries = effectBoundaries();
96 if (hasX())
97 sourceClipRect.setX(boundaries.x());
98 if (hasY())
99 sourceClipRect.setY(boundaries.y());
100 if (hasWidth())
101 sourceClipRect.setWidth(boundaries.width());
102 if (hasHeight())
103 sourceClipRect.setHeight(boundaries.height());
104
105 FloatRect result;
106 if (m_inputEffects.size() > 0) {
107 result = m_inputEffects.at(0)->getSourceRect(sourceRect, sourceClipRect) ;
108 for (unsigned i = 1; i < m_inputEffects.size(); ++i)
109 result.unite(m_inputEffects.at(i)->getSourceRect(sourceRect, sourceC lipRect));
110 } else {
111 result = sourceRect;
112 result.intersect(sourceClipRect);
113 }
114 return result;
115 }
116
117 IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
118 {
119 ASSERT(hasResult());
120 IntPoint location = m_absolutePaintRect.location();
121 location.moveBy(-effectRect.location());
122 return IntRect(location, m_absolutePaintRect.size());
123 }
124
125 IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
126 {
127 return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
128 srcRect.y() - m_absolutePaintRect.y()), srcRect.size ());
129 }
130
131 FilterEffect* FilterEffect::inputEffect(unsigned number) const
132 {
133 ASSERT_WITH_SECURITY_IMPLICATION(number < m_inputEffects.size());
134 return m_inputEffects.at(number).get();
135 }
136
137 void FilterEffect::apply()
138 {
139 if (hasResult())
140 return;
141 unsigned size = m_inputEffects.size();
142 for (unsigned i = 0; i < size; ++i) {
143 FilterEffect* in = m_inputEffects.at(i).get();
144 in->apply();
145 if (!in->hasResult())
146 return;
147
148 // Convert input results to the current effect's color space.
149 transformResultColorSpace(in, i);
150 }
151
152 determineAbsolutePaintRect();
153 setResultColorSpace(m_operatingColorSpace);
154
155 if (!isFilterSizeValid(m_absolutePaintRect))
156 return;
157
158 if (requiresValidPreMultipliedPixels()) {
159 for (unsigned i = 0; i < size; ++i)
160 inputEffect(i)->correctFilterResultIfNeeded();
161 }
162
163 if (applySkia())
164 return;
165
166 applySoftware();
167 }
168
169 void FilterEffect::forceValidPreMultipliedPixels()
170 {
171 // Must operate on pre-multiplied results; other formats cannot have invalid pixels.
172 if (!m_premultipliedImageResult)
173 return;
174
175 Uint8ClampedArray* imageArray = m_premultipliedImageResult.get();
176 unsigned char* pixelData = imageArray->data();
177 int pixelArrayLength = imageArray->length();
178
179 // We must have four bytes per pixel, and complete pixels
180 ASSERT(!(pixelArrayLength % 4));
181
182 #if HAVE(ARM_NEON_INTRINSICS)
183 if (pixelArrayLength >= 64) {
184 unsigned char* lastPixel = pixelData + (pixelArrayLength & ~0x3f);
185 do {
186 // Increments pixelData by 64.
187 uint8x16x4_t sixteenPixels = vld4q_u8(pixelData);
188 sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels. val[3]);
189 sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels. val[3]);
190 sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels. val[3]);
191 vst4q_u8(pixelData, sixteenPixels);
192 pixelData += 64;
193 } while (pixelData < lastPixel);
194
195 pixelArrayLength &= 0x3f;
196 if (!pixelArrayLength)
197 return;
198 }
199 #endif
200
201 int numPixels = pixelArrayLength / 4;
202
203 // Iterate over each pixel, checking alpha and adjusting color components if necessary
204 while (--numPixels >= 0) {
205 // Alpha is the 4th byte in a pixel
206 unsigned char a = *(pixelData + 3);
207 // Clamp each component to alpha, and increment the pixel location
208 for (int i = 0; i < 3; ++i) {
209 if (*pixelData > a)
210 *pixelData = a;
211 ++pixelData;
212 }
213 // Increment for alpha
214 ++pixelData;
215 }
216 }
217
218 void FilterEffect::clearResult()
219 {
220 if (m_imageBufferResult)
221 m_imageBufferResult.clear();
222 if (m_unmultipliedImageResult)
223 m_unmultipliedImageResult.clear();
224 if (m_premultipliedImageResult)
225 m_premultipliedImageResult.clear();
226 }
227
228 void FilterEffect::clearResultsRecursive()
229 {
230 // Clear all results, regardless that the current effect has
231 // a result. Can be used if an effect is in an erroneous state.
232 if (hasResult())
233 clearResult();
234
235 unsigned size = m_inputEffects.size();
236 for (unsigned i = 0; i < size; ++i)
237 m_inputEffects.at(i).get()->clearResultsRecursive();
238 }
239
240 ImageBuffer* FilterEffect::asImageBuffer()
241 {
242 if (!hasResult())
243 return 0;
244 if (m_imageBufferResult)
245 return m_imageBufferResult.get();
246 m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), 1, m_f ilter->renderingMode());
247 IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
248 if (m_premultipliedImageResult)
249 m_imageBufferResult->putByteArray(Premultiplied, m_premultipliedImageRes ult.get(), destinationRect.size(), destinationRect, IntPoint());
250 else
251 m_imageBufferResult->putByteArray(Unmultiplied, m_unmultipliedImageResul t.get(), destinationRect.size(), destinationRect, IntPoint());
252 return m_imageBufferResult.get();
253 }
254
255 PassRefPtr<Uint8ClampedArray> FilterEffect::asUnmultipliedImage(const IntRect& r ect)
256 {
257 ASSERT(isFilterSizeValid(rect));
258 RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized (rect.width() * rect.height() * 4);
259 copyUnmultipliedImage(imageData.get(), rect);
260 return imageData.release();
261 }
262
263 PassRefPtr<Uint8ClampedArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
264 {
265 ASSERT(isFilterSizeValid(rect));
266 RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized (rect.width() * rect.height() * 4);
267 copyPremultipliedImage(imageData.get(), rect);
268 return imageData.release();
269 }
270
271 inline void FilterEffect::copyImageBytes(Uint8ClampedArray* source, Uint8Clamped Array* destination, const IntRect& rect)
272 {
273 // Initialize the destination to transparent black, if not entirely covered by the source.
274 if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width( ) || rect.maxY() > m_absolutePaintRect.height())
275 memset(destination->data(), 0, destination->length());
276
277 // Early return if the rect does not intersect with the source.
278 if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect. width() || rect.y() >= m_absolutePaintRect.height())
279 return;
280
281 int xOrigin = rect.x();
282 int xDest = 0;
283 if (xOrigin < 0) {
284 xDest = -xOrigin;
285 xOrigin = 0;
286 }
287 int xEnd = rect.maxX();
288 if (xEnd > m_absolutePaintRect.width())
289 xEnd = m_absolutePaintRect.width();
290
291 int yOrigin = rect.y();
292 int yDest = 0;
293 if (yOrigin < 0) {
294 yDest = -yOrigin;
295 yOrigin = 0;
296 }
297 int yEnd = rect.maxY();
298 if (yEnd > m_absolutePaintRect.height())
299 yEnd = m_absolutePaintRect.height();
300
301 int size = (xEnd - xOrigin) * 4;
302 int destinationScanline = rect.width() * 4;
303 int sourceScanline = m_absolutePaintRect.width() * 4;
304 unsigned char *destinationPixel = destination->data() + ((yDest * rect.width ()) + xDest) * 4;
305 unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRec t.width()) + xOrigin) * 4;
306
307 while (yOrigin < yEnd) {
308 memcpy(destinationPixel, sourcePixel, size);
309 destinationPixel += destinationScanline;
310 sourcePixel += sourceScanline;
311 ++yOrigin;
312 }
313 }
314
315 void FilterEffect::copyUnmultipliedImage(Uint8ClampedArray* destination, const I ntRect& rect)
316 {
317 ASSERT(hasResult());
318
319 if (!m_unmultipliedImageResult) {
320 // We prefer a conversion from the image buffer.
321 if (m_imageBufferResult)
322 m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImag eData(IntRect(IntPoint(), m_absolutePaintRect.size()));
323 else {
324 ASSERT(isFilterSizeValid(m_absolutePaintRect));
325 m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m _absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
326 unsigned char* sourceComponent = m_premultipliedImageResult->data();
327 unsigned char* destinationComponent = m_unmultipliedImageResult->dat a();
328 unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
329 while (sourceComponent < end) {
330 int alpha = sourceComponent[3];
331 if (alpha) {
332 destinationComponent[0] = static_cast<int>(sourceComponent[0 ]) * 255 / alpha;
333 destinationComponent[1] = static_cast<int>(sourceComponent[1 ]) * 255 / alpha;
334 destinationComponent[2] = static_cast<int>(sourceComponent[2 ]) * 255 / alpha;
335 } else {
336 destinationComponent[0] = 0;
337 destinationComponent[1] = 0;
338 destinationComponent[2] = 0;
339 }
340 destinationComponent[3] = alpha;
341 sourceComponent += 4;
342 destinationComponent += 4;
343 }
344 }
345 }
346 copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
347 }
348
349 void FilterEffect::copyPremultipliedImage(Uint8ClampedArray* destination, const IntRect& rect)
350 {
351 ASSERT(hasResult());
352
353 if (!m_premultipliedImageResult) {
354 // We prefer a conversion from the image buffer.
355 if (m_imageBufferResult)
356 m_premultipliedImageResult = m_imageBufferResult->getPremultipliedIm ageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
357 else {
358 ASSERT(isFilterSizeValid(m_absolutePaintRect));
359 m_premultipliedImageResult = Uint8ClampedArray::createUninitialized( m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
360 unsigned char* sourceComponent = m_unmultipliedImageResult->data();
361 unsigned char* destinationComponent = m_premultipliedImageResult->da ta();
362 unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
363 while (sourceComponent < end) {
364 int alpha = sourceComponent[3];
365 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
366 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
367 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
368 destinationComponent[3] = alpha;
369 sourceComponent += 4;
370 destinationComponent += 4;
371 }
372 }
373 }
374 copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
375 }
376
377 ImageBuffer* FilterEffect::createImageBufferResult()
378 {
379 // Only one result type is allowed.
380 ASSERT(!hasResult());
381 if (m_absolutePaintRect.isEmpty())
382 return 0;
383 m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), 1, m_f ilter->renderingMode());
384 if (!m_imageBufferResult)
385 return 0;
386 ASSERT(m_imageBufferResult->context());
387 return m_imageBufferResult.get();
388 }
389
390 Uint8ClampedArray* FilterEffect::createUnmultipliedImageResult()
391 {
392 // Only one result type is allowed.
393 ASSERT(!hasResult());
394 ASSERT(isFilterSizeValid(m_absolutePaintRect));
395
396 if (m_absolutePaintRect.isEmpty())
397 return 0;
398 m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolut ePaintRect.width() * m_absolutePaintRect.height() * 4);
399 return m_unmultipliedImageResult.get();
400 }
401
402 Uint8ClampedArray* FilterEffect::createPremultipliedImageResult()
403 {
404 // Only one result type is allowed.
405 ASSERT(!hasResult());
406 ASSERT(isFilterSizeValid(m_absolutePaintRect));
407
408 if (m_absolutePaintRect.isEmpty())
409 return 0;
410 m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolu tePaintRect.width() * m_absolutePaintRect.height() * 4);
411 return m_premultipliedImageResult.get();
412 }
413
414 void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
415 {
416 if (!hasResult() || dstColorSpace == m_resultColorSpace)
417 return;
418
419 // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion b y adding
420 // color space transform support for the {pre,un}multiplied arrays.
421 asImageBuffer()->transformColorSpace(m_resultColorSpace, dstColorSpace);
422
423 m_resultColorSpace = dstColorSpace;
424
425 if (m_unmultipliedImageResult)
426 m_unmultipliedImageResult.clear();
427 if (m_premultipliedImageResult)
428 m_premultipliedImageResult.clear();
429 }
430
431 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
432 {
433 // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
434 // possible at the moment, because we need more detailed informations from t he target object.
435 return ts;
436 }
437
438 FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag s flags)
439 {
440 ASSERT(filter());
441
442 // FETile, FETurbulence, FEFlood don't have input effects, take the filter r egion as unite rect.
443 FloatRect subregion;
444 if (unsigned numberOfInputEffects = inputEffects().size()) {
445 subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags);
446 for (unsigned i = 1; i < numberOfInputEffects; ++i)
447 subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(fl ags));
448 } else
449 subregion = filter()->filterRegion();
450
451 // After calling determineFilterPrimitiveSubregion on the target effect, res et the subregion again for <feTile>.
452 if (filterEffectType() == FilterEffectTypeTile)
453 subregion = filter()->filterRegion();
454
455 if (flags & MapRectForward)
456 subregion = mapRect(subregion);
457
458 FloatRect boundaries = effectBoundaries();
459 if (hasX())
460 subregion.setX(boundaries.x());
461 if (hasY())
462 subregion.setY(boundaries.y());
463 if (hasWidth())
464 subregion.setWidth(boundaries.width());
465 if (hasHeight())
466 subregion.setHeight(boundaries.height());
467
468 setFilterPrimitiveSubregion(subregion);
469
470 FloatRect absoluteSubregion = filter()->absoluteTransform().mapRect(subregio n);
471 FloatSize filterResolution = filter()->filterResolution();
472 absoluteSubregion.scale(filterResolution.width(), filterResolution.height()) ;
473
474 // Clip every filter effect to the filter region.
475 if (flags & ClipToFilterRegion) {
476 FloatRect absoluteScaledFilterRegion = filter()->absoluteFilterRegion();
477 absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolut ion.height());
478 absoluteSubregion.intersect(absoluteScaledFilterRegion);
479 }
480
481 setMaxEffectRect(absoluteSubregion);
482 return subregion;
483 }
484
485 PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder * builder)
486 {
487 return 0;
488 }
489
490 SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) c onst
491 {
492 SkRect rect = SkRect::MakeEmpty();
493 uint32_t flags = 0;
494 FloatRect boundaries = effectBoundaries();
495 FloatSize resolution = filter()->filterResolution();
496 boundaries.scale(resolution.width(), resolution.height());
497 boundaries.move(cropOffset);
498 if (hasX()) {
499 rect.fLeft = boundaries.x();
500 flags |= SkImageFilter::CropRect::kHasLeft_CropEdge;
501 }
502 if (hasY()) {
503 rect.fTop = boundaries.y();
504 flags |= SkImageFilter::CropRect::kHasTop_CropEdge;
505 }
506 if (hasWidth()) {
507 rect.fRight = rect.fLeft + boundaries.width();
508 flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
509 }
510 if (hasHeight()) {
511 rect.fBottom = rect.fTop + boundaries.height();
512 flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
513 }
514 return SkImageFilter::CropRect(rect, flags);
515 }
516
517 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/filters/FilterEffect.h ('k') | Source/core/platform/graphics/filters/FilterOperation.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698