void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), op); return; } FloatSize intrinsicTileSize = size(); if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect)) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op); return; } FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPatternCounter.startCounting(); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); drawPatternCounter.stopCounting(); startAnimation(); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { QRectF normalizedDst = dst.normalized(); QRectF normalizedSrc = src.normalized(); startAnimation(); if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) return; QPixmap* image = nativeImageForCurrentFrame(); if (!image) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op); return; } CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); ContextShadow* shadow = ctxt->contextShadow(); if (shadow->m_type != ContextShadow::NoShadow) { QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst); if (shadowPainter) { shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); shadow->endShadowLayer(ctxt); } } ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); ctxt->setCompositeOperation(previousOperator); if (imageObserver()) imageObserver()->didDraw(this); }
// Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; // Spin the animation to the correct frame before we try to draw it, so we // don't draw an old frame and then immediately need to draw a newer one, // causing flicker and wasting CPU. startAnimation(); BBitmap* image = nativeImageForCurrentFrame(); if (!image || !image->IsValid()) // If the image hasn't fully loaded. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } ctxt->save(); ctxt->setCompositeOperation(op); BRect srcRect(src); BRect dstRect(dst); // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html ctxt->platformContext()->SetDrawingMode(B_OP_ALPHA); uint32 options = 0; if (ctxt->imageInterpolationQuality() == InterpolationDefault || ctxt->imageInterpolationQuality() > InterpolationLow) { options |= B_FILTER_BITMAP_BILINEAR; } ctxt->platformContext()->DrawBitmapAsync(image, srcRect, dstRect, options); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void quarterHour(uint8_t hour, uint8_t minute, uint16_t wait) { uint8_t no_rows; uint8_t y; uint8_t x; int16_t j; // light number of rows depending on the hour quarter (floored to be safe) no_rows = floor(minute / 15) * height; // one hour indicator is actually 0 but we want full display no_rows = (no_rows == 0) ? (4 * height) : no_rows; solidColor(0,0,0); // turn them all off show(); if ((hour == 12 || hour == 0 ) && minute == 0) { rainbowCycle(25); // special edition hour for midday } else { // fade columns in and out for (j = 0; j <= 255; j += 5) { for (y = 0; y < no_rows; y++) { for (x = 0; x < PIXEL_ROW; x++) { setPixel(pixelMap[x][y],1,Color(0,0,j)); } } show(); usleep(10*1000); } usleep(wait*1000); // show for 10s for (j = 255; j >= 0; j -= 5) { for (y = 0; y < no_rows; y++) { for (x = 0; x < PIXEL_ROW; x++) { setPixel(pixelMap[x][y],1,Color(0,0,j)); } } show(); usleep(10*1000); } } }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation) { startAnimation(); CGImageRef image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } FloatSize selfSize = currentFrameSize(); ImageOrientation orientation = DefaultImageOrientation; if (shouldRespectImageOrientation == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); ctxt->drawNativeImage(image, selfSize, styleColorSpace, destRect, srcRect, compositeOp, blendMode, orientation); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRectIn, ColorSpace styleColorSpace, CompositeOperator compositeOp) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, compositeOp); else { IntRect intSrcRect(srcRectIn); RefPtr<SharedBitmap> bmp = frameAtIndex(m_currentFrame); if (bmp->width() != m_source.size().width()) { double scaleFactor = static_cast<double>(bmp->width()) / m_source.size().width(); intSrcRect.setX(stableRound(srcRectIn.x() * scaleFactor)); intSrcRect.setWidth(stableRound(srcRectIn.width() * scaleFactor)); intSrcRect.setY(stableRound(srcRectIn.y() * scaleFactor)); intSrcRect.setHeight(stableRound(srcRectIn.height() * scaleFactor)); } bmp->draw(ctxt, enclosingIntRect(dstRect), intSrcRect, styleColorSpace, compositeOp); } startAnimation(); }
void Image::drawPattern(GraphicsContext* context, const FloatRect& src, const AffineTransform& patternTransformation, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& dst) { if (dst.isEmpty() || src.isEmpty()) return; NativeImagePtr image = nativeImageForCurrentFrame(); if (!image) return; startAnimation(); if (mayFillWithSolidColor()) { fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); return; } notImplemented(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (dst.isEmpty() || src.isEmpty()) return; NativeImagePtr image = nativeImageForCurrentFrame(); if (!image) return; startAnimation(); if (mayFillWithSolidColor()) { fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); return; } context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) FloatRect srcRectLocal = adjustSourceRectForDownSampling(src, image->size()); #else FloatRect srcRectLocal(src); #endif context->platformContext()->activePainter()->drawImage(image, dst, srcRectLocal); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), op); return; } #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); wxGraphicsContext* gc = context->GetGraphicsContext(); #else wxWindowDC* context = ctxt->platformContext(); #endif startAnimation(); wxBitmap* bitmap = frameAtIndex(m_currentFrame); if (!bitmap) // If it's too early we won't have an image yet. return; // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html // FIXME: NYI ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); #if USE(WXGC) float scaleX = src.width() / dst.width(); float scaleY = src.height() / dst.height(); FloatRect adjustedDestRect = dst; FloatSize selfSize = currentFrameSize(); if (src.size() != selfSize) { adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. int currHeight = bitmap->GetHeight(); if (currHeight < selfSize.height()) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); #else IntRect srcIntRect(src); IntRect dstIntRect(dst); bool rescaling = false; if ((dstIntRect.width() != srcIntRect.width()) || (dstIntRect.height() != srcIntRect.height())) { rescaling = true; wxImage img = bitmap->ConvertToImage(); img.Rescale(dstIntRect.width(), dstIntRect.height()); bitmap = new wxBitmap(img); } wxMemoryDC mydc; ASSERT(bitmap->GetRefData()); mydc.SelectObject(*bitmap); context->Blit((wxCoord)dstIntRect.x(),(wxCoord)dstIntRect.y(), (wxCoord)dstIntRect.width(), (wxCoord)dstIntRect.height(), &mydc, (wxCoord)srcIntRect.x(), (wxCoord)srcIntRect.y(), wxCOPY, true); mydc.SelectObject(wxNullBitmap); // NB: delete is causing crashes during page load, but not during the deletion // itself. It occurs later on when a valid bitmap created in frameAtIndex // suddenly becomes invalid after returning. It's possible these errors deal // with reentrancy and threding problems. //delete bitmap; if (rescaling) { delete bitmap; bitmap = NULL; } #endif ctxt->restore(); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; CGContextRef context = ctxt->platformContext(); ctxt->save(); bool shouldUseSubimage = false; // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image // and then set a clip to the portion that we want to display. FloatRect adjustedDestRect = destRect; FloatSize selfSize = currentFrameSize(); if (srcRect.size() != selfSize) { CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context); // When the image is scaled using high-quality interpolation, we create a temporary CGImage // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { FloatRect subimageRect = srcRect; float leftPadding = srcRect.x() - floorf(srcRect.x()); float topPadding = srcRect.y() - floorf(srcRect.y()); subimageRect.move(-leftPadding, -topPadding); adjustedDestRect.move(-leftPadding / xScale, -topPadding / yScale); subimageRect.setWidth(ceilf(subimageRect.width() + leftPadding)); adjustedDestRect.setWidth(subimageRect.width() / xScale); subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale)); } CGContextClipToRect(context, destRect); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. if (!shouldUseSubimage && currHeight < selfSize.height()) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); ctxt->setCompositeOperation(compositeOp); // Flip the coords. CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); // Adjust the color space. image = imageWithColorSpace(image.get(), styleColorSpace); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void GraphicsLayerTextureMapper::commitLayerChanges() { if (m_changeMask == NoChanges) return; if (m_changeMask & ChildrenChange) { Vector<TextureMapperLayer*> textureMapperLayerChildren; toTextureMapperLayerVector(children(), textureMapperLayerChildren); m_layer->setChildren(textureMapperLayerChildren); } if (m_changeMask & MaskLayerChange) m_layer->setMaskLayer(toTextureMapperLayer(maskLayer())); if (m_changeMask & ReplicaLayerChange) m_layer->setReplicaLayer(toTextureMapperLayer(replicaLayer())); if (m_changeMask & PositionChange) m_layer->setPosition(position()); if (m_changeMask & AnchorPointChange) m_layer->setAnchorPoint(anchorPoint()); if (m_changeMask & SizeChange) m_layer->setSize(size()); if (m_changeMask & TransformChange) m_layer->setTransform(transform()); if (m_changeMask & ChildrenTransformChange) m_layer->setChildrenTransform(childrenTransform()); if (m_changeMask & Preserves3DChange) m_layer->setPreserves3D(preserves3D()); if (m_changeMask & ContentsRectChange) m_layer->setContentsRect(contentsRect()); if (m_changeMask & MasksToBoundsChange) m_layer->setMasksToBounds(masksToBounds()); if (m_changeMask & DrawsContentChange) m_layer->setDrawsContent(drawsContent()); if (m_changeMask & ContentsVisibleChange) m_layer->setContentsVisible(contentsAreVisible()); if (m_changeMask & ContentsOpaqueChange) m_layer->setContentsOpaque(contentsOpaque()); if (m_changeMask & BackfaceVisibilityChange) m_layer->setBackfaceVisibility(backfaceVisibility()); if (m_changeMask & OpacityChange) m_layer->setOpacity(opacity()); if (m_changeMask & BackgroundColorChange) m_layer->setSolidColor(solidColor()); #if ENABLE(CSS_FILTERS) if (m_changeMask & FilterChange) m_layer->setFilters(filters()); #endif if (m_changeMask & BackingStoreChange) m_layer->setBackingStore(m_backingStore); if (m_changeMask & DebugVisualsChange) m_layer->setDebugVisuals(isShowingDebugBorder(), debugBorderColor(), debugBorderWidth(), isShowingRepaintCounter()); if (m_changeMask & RepaintCountChange) m_layer->setRepaintCount(repaintCount()); if (m_changeMask & ContentChange) m_layer->setContentsLayer(platformLayer()); if (m_changeMask & AnimationChange) m_layer->setAnimations(m_animations); if (m_changeMask & AnimationStarted) client()->notifyAnimationStarted(this, m_animationStartTime); if (m_changeMask & FixedToViewporChange) m_layer->setFixedToViewport(fixedToViewport()); if (m_changeMask & IsScrollableChange) m_layer->setIsScrollable(isScrollable()); if (m_changeMask & CommittedScrollOffsetChange) m_layer->didCommitScrollOffset(m_committedScrollOffset); m_changeMask = NoChanges; }
// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& tileScaleFactor, TileRule hRule, TileRule vRule, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dstRect, solidColor(), op); return; } FloatSize tileScale = tileScaleFactor; FloatSize spacing; // FIXME: These rules follow CSS border-image rules, but they should not be down here in Image. bool centerOnGapHorizonally = false; bool centerOnGapVertically = false; switch (hRule) { case RoundTile: { int numItems = std::max<int>(floorf(dstRect.width() / srcRect.width()), 1); tileScale.setWidth(dstRect.width() / (srcRect.width() * numItems)); break; } case SpaceTile: { int numItems = floorf(dstRect.width() / srcRect.width()); if (!numItems) return; spacing.setWidth((dstRect.width() - srcRect.width() * numItems) / (numItems + 1)); tileScale.setWidth(1); centerOnGapHorizonally = !(numItems & 1); break; } case StretchTile: case RepeatTile: break; } switch (vRule) { case RoundTile: { int numItems = std::max<int>(floorf(dstRect.height() / srcRect.height()), 1); tileScale.setHeight(dstRect.height() / (srcRect.height() * numItems)); break; } case SpaceTile: { int numItems = floorf(dstRect.height() / srcRect.height()); if (!numItems) return; spacing.setHeight((dstRect.height() - srcRect.height() * numItems) / (numItems + 1)); tileScale.setHeight(1); centerOnGapVertically = !(numItems & 1); break; } case StretchTile: case RepeatTile: break; } AffineTransform patternTransform = AffineTransform().scaleNonUniform(tileScale.width(), tileScale.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). float hPhase = tileScale.width() * srcRect.x(); float vPhase = tileScale.height() * srcRect.y(); float scaledTileWidth = tileScale.width() * srcRect.width(); float scaledTileHeight = tileScale.height() * srcRect.height(); if (centerOnGapHorizonally) hPhase -= spacing.width(); else if (hRule == Image::RepeatTile || hRule == Image::SpaceTile) hPhase -= (dstRect.width() - scaledTileWidth) / 2; if (centerOnGapVertically) vPhase -= spacing.height(); else if (vRule == Image::RepeatTile || vRule == Image::SpaceTile) vPhase -= (dstRect.height() - scaledTileHeight) / 2; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); drawPattern(ctxt, srcRect, patternTransform, patternPhase, spacing, op, dstRect); #if PLATFORM(IOS) startAnimation(DoNotCatchUp); #else startAnimation(); #endif }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || srcRect.width() == 0.0f || srcRect.height() == 0.0f) return; startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); return; } IntSize selfSize = size(); cairo_t* cr = context->platformContext(); context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD); float scaleX = srcRect.width() / dstRect.width(); float scaleY = srcRect.height() / dstRect.height(); cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; cairo_pattern_set_matrix(pattern, &matrix); // Draw the shadow #if ENABLE(FILTERS) FloatSize shadowOffset; float shadowBlur; Color shadowColor; if (context->getShadow(shadowOffset, shadowBlur, shadowColor)) { IntSize shadowBufferSize; FloatRect shadowRect; float radius = 0; context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, dstRect, shadowOffset, shadowBlur); shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f); //draw shadow into a new ImageBuffer OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); cairo_t* shadowContext = shadowBuffer->context()->platformContext(); cairo_set_source(shadowContext, pattern); cairo_translate(shadowContext, -dstRect.x(), -dstRect.y()); cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); cairo_fill(shadowContext); context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); } #endif // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); cairo_set_source(cr, pattern); cairo_pattern_destroy(pattern); cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height()); cairo_clip(cr); cairo_paint_with_alpha(cr, context->getAlpha()); context->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), op); return; } ASSERT(!isBitmapImage() || notSolidColor()); #if PLATFORM(IOS) FloatSize intrinsicTileSize = originalSize(); #else FloatSize intrinsicTileSize = size(); #endif if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); FloatRect oneTileRect; FloatSize actualTileSize(scaledTileSize.width() + spacing.width(), scaledTileSize.height() + spacing.height()); oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), actualTileSize.width()) - actualTileSize.width(), actualTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), actualTileSize.height()) - actualTileSize.height(), actualTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect) && !ctxt.drawLuminanceMask()) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op, blendMode, ImageOrientationDescription()); return; } #if PLATFORM(IOS) // When using accelerated drawing on iOS, it's faster to stretch an image than to tile it. if (ctxt.isAcceleratedContext()) { if (size().width() == 1 && intersection(oneTileRect, destRect).height() == destRect.height()) { FloatRect visibleSrcRect; visibleSrcRect.setX(0); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(1); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, ImageOrientationDescription()); return; } if (size().height() == 1 && intersection(oneTileRect, destRect).width() == destRect.width()) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY(0); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(1); draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, ImageOrientationDescription()); return; } } #endif // Patterned images and gradients can use lots of memory for caching when the // tile size is large (<rdar://problem/4691859>, <rdar://problem/6239505>). // Memory consumption depends on the transformed tile size which can get // larger than the original tile if user zooms in enough. #if PLATFORM(IOS) const float maxPatternTilePixels = 512 * 512; #else const float maxPatternTilePixels = 2048 * 2048; #endif FloatRect transformedTileSize = ctxt.getCTM().mapRect(FloatRect(FloatPoint(), scaledTileSize)); float transformedTileSizePixels = transformedTileSize.width() * transformedTileSize.height(); FloatRect currentTileRect = oneTileRect; if (transformedTileSizePixels > maxPatternTilePixels) { GraphicsContextStateSaver stateSaver(ctxt); ctxt.clip(destRect); currentTileRect.shiftYEdgeTo(destRect.y()); float toY = currentTileRect.y(); while (toY < destRect.maxY()) { currentTileRect.shiftXEdgeTo(destRect.x()); float toX = currentTileRect.x(); while (toX < destRect.maxX()) { FloatRect toRect(toX, toY, currentTileRect.width(), currentTileRect.height()); FloatRect fromRect(toFloatPoint(currentTileRect.location() - oneTileRect.location()), currentTileRect.size()); fromRect.scale(1 / scale.width(), 1 / scale.height()); draw(ctxt, toRect, fromRect, op, BlendModeNormal, ImageOrientationDescription()); toX += currentTileRect.width(); currentTileRect.shiftXEdgeTo(oneTileRect.x()); } toY += currentTileRect.height(); currentTileRect.shiftYEdgeTo(oneTileRect.y()); } return; } AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), spacing, op, destRect, blendMode); #if PLATFORM(IOS) startAnimation(DoNotCatchUp); #else startAnimation(); #endif }
void App::onGraphics3D(RenderDevice* rd, Array<shared_ptr<Surface> >& allSurfaces) { // This implementation is equivalent to the default GApp's. It is repeated here to make it // easy to modify rendering. If you don't require custom rendering, just delete this // method from your application and rely on the base class. if (!scene()) { if ((submitToDisplayMode() == SubmitToDisplayMode::MAXIMIZE_THROUGHPUT) && (!rd->swapBuffersAutomatically())) { swapBuffers(); } rd->clear(); rd->pushState(); { rd->setProjectionAndCameraMatrix(activeCamera()->projection(), activeCamera()->frame()); drawDebugShapes(); } rd->popState(); return; } updateAudioData(); if (System::time() - m_lastInterestingEventTime > 10.0) { if (Random::common().uniform() < 0.001f) { if (m_sonicSculpturePieces.size() > 0) { int index = Random::common().integer(0, m_sonicSculpturePieces.size() - 1); generatePlayPulse(m_sonicSculpturePieces[index]); m_lastInterestingEventTime = System::time(); } } } handlePlayPulses(); GBuffer::Specification gbufferSpec = m_gbufferSpecification; extendGBufferSpecification(gbufferSpec); m_gbuffer->setSpecification(gbufferSpec); m_gbuffer->resize(m_framebuffer->width(), m_framebuffer->height()); m_gbuffer->prepare(rd, activeCamera(), 0, -(float)previousSimTimeStep(), m_settings.depthGuardBandThickness, m_settings.colorGuardBandThickness); m_renderer->render(rd, m_framebuffer, m_depthPeelFramebuffer, scene()->lightingEnvironment(), m_gbuffer, allSurfaces); // Debug visualizations and post-process effects rd->pushState(m_framebuffer); { // Call to make the App show the output of debugDraw(...) rd->setProjectionAndCameraMatrix(activeCamera()->projection(), activeCamera()->frame()); for (auto& piece : m_sonicSculpturePieces) { piece->render(rd, scene()->lightingEnvironment()); } if (notNull(m_currentSonicSculpturePiece)) { m_currentSonicSculpturePiece->render(rd, scene()->lightingEnvironment()); } for (int i = m_playPlanes.size() - 1; i >= 0; --i) { const PlayPlane& pp = m_playPlanes[i]; if (pp.endWindowIndex < g_sampleWindowIndex) { m_playPlanes.remove(i); } Point3 point = pp.origin + (pp.direction * METERS_PER_SAMPLE_WINDOW * (g_sampleWindowIndex-pp.beginWindowIndex)); Color4 solidColor(1.0f, .02f, .03f, .15f); // Plane plane(point, pp.direction); // Draw::plane(plane, rd, solidColor, Color4::clear()); CFrame planeFrame = pp.frame; planeFrame.translation = point; Vector3 minP(finf(), finf(), finf()); Vector3 maxP(-finf(), -finf(), -finf()); for (auto& piece : m_sonicSculpturePieces) { piece->minMaxValue(planeFrame, minP, maxP); } Box b(Vector3(minP.xy()-Vector2(3,3), 0.0f), Vector3(maxP.xy() + Vector2(3, 3), 0.1f), planeFrame); Draw::box(b, rd, solidColor, Color4::clear()); } drawDebugShapes(); const shared_ptr<Entity>& selectedEntity = (notNull(developerWindow) && notNull(developerWindow->sceneEditorWindow)) ? developerWindow->sceneEditorWindow->selectedEntity() : shared_ptr<Entity>(); scene()->visualize(rd, selectedEntity, allSurfaces, sceneVisualizationSettings(), activeCamera()); // Post-process special effects m_depthOfField->apply(rd, m_framebuffer->texture(0), m_framebuffer->texture(Framebuffer::DEPTH), activeCamera(), m_settings.depthGuardBandThickness - m_settings.colorGuardBandThickness); m_motionBlur->apply(rd, m_framebuffer->texture(0), m_gbuffer->texture(GBuffer::Field::SS_EXPRESSIVE_MOTION), m_framebuffer->texture(Framebuffer::DEPTH), activeCamera(), m_settings.depthGuardBandThickness - m_settings.colorGuardBandThickness); } rd->popState(); rd->push2D(m_framebuffer); { rd->setBlendFunc(RenderDevice::BLEND_SRC_ALPHA, RenderDevice::BLEND_ONE_MINUS_SRC_ALPHA); Array<SoundInstance> soundInstances; Synthesizer::global->getSoundInstances(soundInstances); int xOffset = 10; Vector2 dim(256,100); for (int i = 0; i < soundInstances.size(); ++i) { int yOffset = rd->height() - 120 - (120 * i); Draw::rect2D(Rect2D::xywh(Point2(xOffset, yOffset), dim), rd, Color3::white(), soundInstances[i].displayTexture()); float playheadAlpha = ((float)soundInstances[i].currentPosition) / soundInstances[i].audioSample->buffer.size(); float playheadX = xOffset + (playheadAlpha * dim.x); Draw::rect2D(Rect2D::xywh(Point2(playheadX, yOffset), Vector2(1, dim.y)), rd, Color3::yellow()); } static shared_ptr<GFont> font = GFont::fromFile(System::findDataFile("arial.fnt")); float time = System::time() - m_initialTime; if (time < 10.0f) { float fontAlpha = time < 9.0f ? 1.0f : 10.0f - time; font->draw2D(rd, "Press Space to Sculpt", Vector2(rd->width()/2, rd->height()-100.0f), 30.0f, Color4(Color3::black(), fontAlpha), Color4(Color3::white()*0.6f, fontAlpha), GFont::XALIGN_CENTER); } } rd->pop2D(); if ((submitToDisplayMode() == SubmitToDisplayMode::MAXIMIZE_THROUGHPUT) && (!renderDevice->swapBuffersAutomatically())) { // We're about to render to the actual back buffer, so swap the buffers now. // This call also allows the screenshot and video recording to capture the // previous frame just before it is displayed. swapBuffers(); } // Clear the entire screen (needed even though we'll render over it, since // AFR uses clear() to detect that the buffer is not re-used.) rd->clear(); // Perform gamma correction, bloom, and SSAA, and write to the native window frame buffer m_film->exposeAndRender(rd, activeCamera()->filmSettings(), m_framebuffer->texture(0)); }
void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { SDL_Surface* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; FloatRect sourceRect(src); FloatRect destRect(dst); if (mayFillWithSolidColor()) { fillWithSolidColor(context, destRect, solidColor(), op); return; } // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) context->setCompositeOperation(CompositeCopy); else context->setCompositeOperation(op); SDL_Surface* cr = context->platformContext(); float scaleX = destRect.width() / sourceRect.width(); float scaleY = destRect.height() / sourceRect.height(); // Draw the image. SDL_Rect srcRect, dstRect; srcRect.x = static_cast<Sint16>(src.x()); srcRect.y = static_cast<Sint16>(src.y()); if (0 == sourceRect.width()) srcRect.w = image->w; else srcRect.w = static_cast<Uint16>(sourceRect.width()); if (0 == sourceRect.height()) srcRect.h = image->h; else srcRect.h = static_cast<Uint16>(sourceRect.height()); dstRect.x = static_cast<Sint16>(destRect.x() + context->origin().x()); dstRect.y = static_cast<Sint16>(destRect.y() + context->origin().y()); dstRect.w = static_cast<Sint16>(destRect.width()); dstRect.h = static_cast<Sint16>(destRect.height()); if ((scaleX != 1.0)||(scaleY != 1.0)) { srcRect.x = static_cast<Sint16>(src.x() * scaleX); srcRect.y = static_cast<Sint16>(src.y() * scaleY); srcRect.w = dstRect.w; srcRect.h = dstRect.h; } if (sourceRect != destRect) { if (context->transparencyLayer() == 1.0) { if ((scaleX != 1.0) || (scaleY != 1.0)) { SDL_Surface *surface = zoomSurface(image, scaleX, scaleY, SMOOTHING_OFF); SDL_BlitSurface(surface, &srcRect, cr, &dstRect); SDL_FreeSurface(surface); } else SDL_BlitSurface(image, &srcRect, cr, &dstRect); } else { SDL_Surface *surfaceWithAlpha = applyTransparency(image, static_cast<int> (context->transparencyLayer() * 255)); if ((scaleX != 1.0) || (scaleY != 1.0)) { SDL_Surface *surface = zoomSurface(surfaceWithAlpha, scaleX, scaleY, SMOOTHING_OFF); SDL_BlitSurface(surface, &srcRect, cr, &dstRect); SDL_FreeSurface(surface); } else SDL_BlitSurface(surfaceWithAlpha, &srcRect, cr, &dstRect); SDL_FreeSurface(surfaceWithAlpha); } } else if (context->transparencyLayer() == 1.0) SDL_BlitSurface(image, &srcRect, cr, &dstRect); else { SDL_Surface *surfaceWithAlpha = applyTransparency(image, static_cast<int> (context->transparencyLayer() * 255)); SDL_BlitSurface(surfaceWithAlpha, &srcRect, cr, &dstRect); SDL_FreeSurface(surfaceWithAlpha); } startAnimation(); if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::readyWRATHWidgets(PaintedWidgetsOfWRATHHandleT<Image>& handle, ContextOfWRATH *ctx, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { BitmapImage_readyWRATHWidgets *d(BitmapImage_readyWRATHWidgets::object(this, handle)); ContextOfWRATH::AutoPushNode autoPushRoot(ctx, d->m_root_node); d->m_solid_color.visible(false); if (d->m_image_rect_item.widget()) d->m_image_rect_item.widget()->visible(false); FloatRect normalizedDst = dst.normalized(); FloatRect normalizedSrc = src.normalized(); startAnimation(); if (normalizedSrc.isEmpty() || normalizedDst.isEmpty()) return; NativeImagePtr nativeImage = nativeImageForCurrentFrame(); if (!nativeImage) return; // "Hardcode" the requirement for the underlying wrath image type to WRATHImage. // The reason is support for setting texture coordinates, which isn't possible for WRATHCompoundImage WRATHImage* image = nativeImage->getWrathImage(); if (!image) return; if (mayFillWithSolidColor()) { d->m_solid_color.visible(true); readyWRATHWidgetSolidColor(d->m_solid_color, ctx, this, normalizedDst, solidColor(), styleColorSpace, op); return; } // ImageRectOfWRATH methods handle changing the op with respect to composite operator /* CompositeOperator previousOperator = ctxt->compositeOperation(); ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); */ if(!nativeImage->hasAlpha() && op == CompositeSourceOver) { op=CompositeCopy; } /* [WRATH-DANGER]: No shadows ContextShadow* shadow = ctxt->contextShadow(); if (shadow->m_type != ContextShadow::NoShadow) { QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst); if (shadowPainter) { shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255); shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc); shadow->endShadowLayer(ctxt); } } */ /* [WRATH-DANGER]: Possible rounding errors from converting to IntRect */ d->m_image_rect_item.update(ctx, nativeImage, normalizedDst, IntRect(normalizedSrc), op); if (d->m_image_rect_item.widget()) d->m_image_rect_item.widget()->visible(true); /* ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); */ /* ctxt->setCompositeOperation(previousOperator); */ if (imageObserver()) imageObserver()->didDraw(this); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); wxGraphicsContext* gc = context->GetGraphicsContext(); wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame); #else wxDC* context = ctxt->platformContext(); wxBitmap* bitmap = frameAtIndex(m_currentFrame); #endif startAnimation(); if (!bitmap) // If it's too early we won't have an image yet. return; // If we're drawing a sub portion of the image or scaling then create // a pattern transformation on the image and draw the transformed pattern. // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html // FIXME: NYI ctxt->save(); // Set the compositing operation. ctxt->setCompositeOperation(op); #if USE(WXGC) float scaleX = src.width() / dst.width(); float scaleY = src.height() / dst.height(); FloatRect adjustedDestRect = dst; FloatSize selfSize = currentFrameSize(); if (src.size() != selfSize) { adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); } gc->Clip(dst.x(), dst.y(), dst.width(), dst.height()); #if wxCHECK_VERSION(2,9,0) gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); #else gc->DrawGraphicsBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); #endif #else // USE(WXGC) bitmap = getCachedResizedBitmap(bitmap, dst.size(), src); context->DrawBitmap(*bitmap, dst.x(), dst.y(), true); #endif ctxt->restore(); if (ImageObserver* observer = imageObserver()) observer->didDraw(this); }