From 77df848e127b63ad5104417154b1ed184683a898 Mon Sep 17 00:00:00 2001 From: Kacper Kasper Date: Tue, 16 Dec 2025 21:18:45 +0100 Subject: [PATCH] Rework alpha blending support to enable box-shadow * fillRect needs to draw a bitmap instead of using FillRect because the latter is not affected by blending modes. * Removed PushState and PopState calls from most places because they reset transform too. * Regular shadows work, inset shadows do not, fillPath WIP. * This isn't ready for production because most sites still render half-transparent rectangles in place of shadows. --- .../WebCore/platform/graphics/ShadowBlur.cpp | 1 + .../graphics/haiku/GraphicsContextHaiku.cpp | 360 ++++++++++++------ .../graphics/haiku/GraphicsContextHaiku.h | 7 +- .../graphics/haiku/ImageBufferHaiku.cpp | 4 +- .../platform/graphics/haiku/PathHaiku.cpp | 83 +--- 5 files changed, 253 insertions(+), 202 deletions(-) diff --git a/Source/WebCore/platform/graphics/ShadowBlur.cpp b/Source/WebCore/platform/graphics/ShadowBlur.cpp index 36831b00feec9..c070ce2bf7c2f 100644 --- a/Source/WebCore/platform/graphics/ShadowBlur.cpp +++ b/Source/WebCore/platform/graphics/ShadowBlur.cpp @@ -908,6 +908,7 @@ void ShadowBlur::blurShadowBuffer(ImageBuffer& layerImage, const IntSize& templa if (!layerData) return; + printf("blurShadowBuffer, layerData->size() = %d %d\n", layerData->size().width(), layerData->size().height()); blurLayerImage(layerData->bytes(), layerData->size(), layerData->size().width() * 4); layerImage.putPixelBuffer(*layerData, blurRect); } diff --git a/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp index 2aa317575486f..efa5fdc500472 100644 --- a/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp +++ b/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -38,8 +38,10 @@ #include "NotImplemented.h" #include "Path.h" #include "TransformationMatrix.h" +#include "ShadowBlur.h" #include +#include #include #include #include @@ -48,15 +50,33 @@ #include #include -//#define TRACE_GRAPHICS_HAIKU +#define TRACE_GRAPHICS_HAIKU #ifdef TRACE_GRAPHICS_HAIKU # define HGTRACE(x) printf x #else # define HGTRACE(x) ; #endif +#define HGTRACEX(x) printf x -namespace WebCore { +namespace { + +class BlendModeGuard { + BView* m_view; + source_alpha m_sa; + alpha_function m_af; +public: + BlendModeGuard(BView* view): m_view(view) { + m_view->GetBlendingMode(&m_sa, &m_af); + } + + ~BlendModeGuard() { + m_view->SetBlendingMode(m_sa, m_af); + } +}; + +} +namespace WebCore { GraphicsContextHaiku::GraphicsContextHaiku(BView* view) : GraphicsContext(IsDeferred::No, { @@ -70,8 +90,15 @@ GraphicsContextHaiku::GraphicsContextHaiku(BView* view) }) , m_view(view) , m_strokeStyle(B_SOLID_HIGH) + , m_painter(nullptr) { didUpdateState(m_state); + + m_fillBitmap = new BBitmap(BRect(0, 0, 5, 5), B_RGBA32); + memset(m_fillBitmap->Bits(), 0, m_fillBitmap->BitsLength()); + + m_view->SetDrawingMode(B_OP_ALPHA); + m_view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); } GraphicsContextHaiku::~GraphicsContextHaiku() @@ -102,14 +129,15 @@ void GraphicsContextHaiku::drawNativeImage(NativeImage& image, const FloatRect& void GraphicsContextHaiku::drawBitmap(BBitmap* image, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options) { - HGTRACE(("drawBitmap: src([%f:%f] [%f:%f])\n", srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height())); - HGTRACE((" dest([%f:%f] [%f:%f])\n", destRect.x(), destRect.y(), destRect.width(), destRect.height())); - m_view->PushState(); + HGTRACEX(("drawBitmap: src([%f:%f] [%f:%f])\n", srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height())); + HGTRACEX((" dest([%f:%f] [%f:%f])\n", destRect.x(), destRect.y(), destRect.width(), destRect.height())); + + BlendModeGuard guard(m_view); setCompositeOperation(options.compositeOperator()); // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html - m_view->SetDrawingMode(B_OP_ALPHA); + //m_view->SetDrawingMode(B_OP_ALPHA); uint32 flags = 0; @@ -117,9 +145,9 @@ void GraphicsContextHaiku::drawBitmap(BBitmap* image, const FloatRect& destRect, if (options.interpolationQuality() > InterpolationQuality::Low) flags |= B_FILTER_BITMAP_BILINEAR; - m_view->DrawBitmapAsync(image, BRect(srcRect), BRect(destRect), flags); - - m_view->PopState(); + // FIXME: Async doesn't draw shadows (rarely they do appear, + // so there is a data race somewhere) + m_view->DrawBitmap(image, BRect(srcRect), BRect(destRect), flags); } // This is only used to draw borders. @@ -182,7 +210,7 @@ void GraphicsContextHaiku::strokeRect(const FloatRect& rect, float width) void GraphicsContextHaiku::strokePath(const Path& path) { - HGTRACE(("strokePath: (--todo print values)\n")); + HGTRACEX(("strokePath: (--todo print values)\n")); m_view->MovePenTo(B_ORIGIN); // TODO: stroke the shadow (cf shadowAndStrokeCurrentCairoPath) @@ -194,50 +222,77 @@ void GraphicsContextHaiku::strokePath(const Path& path) // BGradient* gradient = m_state.strokeGradient->platformGradient(); // m_view->StrokeShape(shape(), *gradient); } else if (strokeColor().isVisible()) { - drawing_mode mode = m_view->DrawingMode(); - if (m_view->HighColor().alpha < 255) - m_view->SetDrawingMode(B_OP_ALPHA); - m_view->StrokeShape(path.platformPath(), m_strokeStyle); - m_view->SetDrawingMode(mode); } } void GraphicsContextHaiku::fillRect(const FloatRect& rect, const Color& color) { - HGTRACE(("fillRect(color): [%f:%f] [%f:%f]\n", rect.x(), rect.y(), rect.width(), rect.height())); - rgb_color previousColor = m_view->HighColor(); + HGTRACEX(("fillRect(color): [%f:%f] [%f:%f]\n", rect.x(), rect.y(), rect.width(), rect.height())); -#if 0 - // FIXME needs support for Composite SourceIn. - if (hasShadow()) { - shadowBlur().drawRectShadow(this, rect, RoundedRect::Radii()); + if (hasDropShadow()) { + HGTRACE(("hasDropShadow begin\n")); + const auto shadow = dropShadow(); + ShadowBlur contextShadow(*shadow, shadowsIgnoreTransforms()); + contextShadow.drawRectShadow(*this, FloatRoundedRect(rect)); + HGTRACE(("hasDropShadow end\n")); } -#endif - - //setPlatformFillColor(color, ColorSpaceDeviceRGB); - m_view->SetHighColor(color); - m_view->FillRect(rect); - - m_view->SetHighColor(previousColor); + + // FillRect doesn't respect blending modes, DrawBitmap does + const auto [r, g, b, a] = color.toColorTypeLossy>().resolved(); + const uint32_t c = ((a << 24) | (r << 16) | (g << 8) | b); + m_fillBitmap->Lock(); + uint32_t *bits = reinterpret_cast(m_fillBitmap->Bits()); + if(bits[0] != c) { + std::fill(bits, bits + m_fillBitmap->BitsLength() / 4, c); + } + // cannot be async because bitmap might change before the draw is executed + m_view->DrawTiledBitmap(m_fillBitmap, BRect(rect)); + m_fillBitmap->Unlock(); } -void GraphicsContextHaiku::fillRect(const FloatRect& rect, RequiresClipToRect) +void GraphicsContextHaiku::fillRect(const FloatRect& rect, RequiresClipToRect requiresClipToRect) { - HGTRACE(("fillRect: [%f:%f] [%f:%f]\n", rect.x(), rect.y(), rect.width(), rect.height())); - // TODO fill the shadow - m_view->FillRect(rect, B_SOLID_LOW); + HGTRACEX(("fillRect: [%f:%f] [%f:%f]\n", rect.x(), rect.y(), rect.width(), rect.height())); + if (RefPtr fillGradient = this->fillGradient()) { + fillRect(rect, *fillGradient, fillGradientSpaceTransform(), requiresClipToRect); + return; + } + + if (hasDropShadow()) { + HGTRACE(("hasDropShadow begin\n")); + const auto shadow = dropShadow(); + ShadowBlur contextShadow(*shadow, shadowsIgnoreTransforms()); + contextShadow.drawRectShadow(*this, FloatRoundedRect(rect)); + HGTRACE(("hasDropShadow end\n")); + } + // FillRect doesn't respect blending modes, DrawBitmap does + const auto [r, g, b, a] = state().fillBrush().color().toColorTypeLossy>().resolved(); + const uint32_t c = ((a << 24) | (r << 16) | (g << 8) | b); + m_fillBitmap->Lock(); + uint32_t *bits = reinterpret_cast(m_fillBitmap->Bits()); + if(bits[0] != c) { + std::fill(bits, bits + m_fillBitmap->BitsLength() / 4, c); + } + // cannot be async because bitmap might change before the draw is executed + m_view->DrawTiledBitmap(m_fillBitmap, BRect(rect)); + m_fillBitmap->Unlock(); } -void GraphicsContextHaiku::fillRect(const WebCore::FloatRect& r, WebCore::Gradient& g, const WebCore::AffineTransform&, RequiresClipToRect) +void GraphicsContextHaiku::fillRect(const WebCore::FloatRect& r, WebCore::Gradient& g, const WebCore::AffineTransform&, RequiresClipToRect requiresClipToRect) { + HGTRACEX(("fillRect(gradient): [%f:%f] [%f:%f]\n", r.x(), r.y(), r.width(), r.height())); + if (requiresClipToRect == RequiresClipToRect::Yes) { + m_view->ClipToRect(r); + } + // TODO handle the transform m_view->FillRect(r, g.getHaikuGradient()); } void GraphicsContextHaiku::fillRoundedRectImpl(const FloatRoundedRect& roundRect, const Color& color) { - HGTRACE(("fillRoundedRectImpl: (--todo print values)\n")); + HGTRACE(("fillRoundedRectImpl: [%f:%f] [%f:%f]\n", roundRect.rect().x(), roundRect.rect().y(), roundRect.rect().width(), roundRect.rect().height())); if (!color.isVisible()) return; @@ -247,11 +302,13 @@ void GraphicsContextHaiku::fillRoundedRectImpl(const FloatRoundedRect& roundRect const FloatSize& bottomLeft = roundRect.radii().bottomLeft(); const FloatSize& bottomRight = roundRect.radii().bottomRight(); -#if 0 - // FIXME needs support for Composite SourceIn. - if (hasShadow()) - shadowBlur().drawRectShadow(this, rect, FloatRoundedRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); -#endif + if (hasDropShadow()) { + HGTRACE(("hasDropShadow begin\n")); + const auto shadow = dropShadow(); + ShadowBlur contextShadow(*shadow, shadowsIgnoreTransforms()); + contextShadow.drawRectShadow(*this, roundRect); + HGTRACE(("hasDropShadow end\n")); + } BPoint points[3]; const float kRadiusBezierScale = 1.0f - 0.5522847498f; // 1 - (sqrt(2) - 1) * 4 / 3 @@ -299,29 +356,92 @@ void GraphicsContextHaiku::fillRoundedRectImpl(const FloatRoundedRect& roundRect m_view->SetHighColor(oldColor); } -void GraphicsContextHaiku::fillPath(const Path& path) +void GraphicsContextHaiku::fillRectWithRoundedHole(const FloatRect& rect, const FloatRoundedRect& roundedHoleRect, const Color& color) { - HGTRACE(("fillPath: (--todo print values)\n")); - m_view->SetFillRule(fillRule() == WindRule::NonZero ? B_NONZERO : B_EVEN_ODD); - m_view->MovePenTo(B_ORIGIN); + HGTRACEX(("fillRectWithRoundedHole: [%f:%f] [%f:%f] hole: [%f:%f] [%f:%f]\n", + rect.x(), rect.y(), rect.width(), rect.height(), + roundedHoleRect.rect().x(), roundedHoleRect.rect().y(), roundedHoleRect.rect().width(), roundedHoleRect.rect().height())); + Path path; + path.addRect(rect); - // TODO: Render the shadow (cf shadowAndFillCurrentCairoPath) - drawing_mode mode = m_view->DrawingMode(); + if (!roundedHoleRect.radii().isZero()) + path.addRoundedRect(roundedHoleRect); + else + path.addRect(roundedHoleRect.rect()); + + WindRule oldFillRule = fillRule(); + Color oldFillColor = fillColor(); + + setFillRule(WindRule::EvenOdd); + setFillColor(color); + + if (hasDropShadow()) { + HGTRACE(("hasDropShadow begin\n")); + const auto shadow = dropShadow(); + ASSERT(shadow); + + ShadowBlur contextShadow(*shadow, shadowsIgnoreTransforms()); + contextShadow.drawInsetShadow(*this, rect, roundedHoleRect); + HGTRACE(("hasDropShadow end\n")); + } - if (m_state.fillBrush().pattern()) + fillPath(path); + + setFillRule(oldFillRule); + setFillColor(oldFillColor); +} + +void GraphicsContextHaiku::fillPath(const Path& path) +{ + FloatRect rect = path.fastBoundingRect(); + FloatSize layerSize = getCTM().mapSize(rect.size()); + FloatRect mappedRect = getCTM().mapRect(rect); + HGTRACE(("fillPath: fastBoundingRect = [%f:%f] [%f:%f], mappedRect = [%f %f]\n", + rect.x(), rect.y(), rect.width(), rect.height(), mappedRect.x(), mappedRect.y())); + BRect pathBounds = BRect(0, 0, rect.width() + 1, rect.height() + 1); + BBitmap *pathBitmap = new BBitmap(pathBounds, B_RGBA32, true, false); + if(m_painter == nullptr) { + m_painter = new BView(pathBounds, "painter", B_FOLLOW_ALL, B_WILL_DRAW); + } + if(!m_painter->Bounds().Contains(pathBounds)) { + m_painter->ResizeTo(pathBounds.Size()); + } + pathBitmap->AddChild(m_painter); + pathBitmap->Lock(); + m_painter->PushState(); + m_painter->SetFillRule(fillRule() == WindRule::NonZero ? B_NONZERO : B_EVEN_ODD); + //m_painter->TranslateBy(-rect.x(), -rect.y()); + m_painter->MovePenTo(B_ORIGIN); + m_painter->SetDrawingMode(B_OP_ALPHA); + m_painter->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + + // TODO: renderShadow + + if (m_state.fillBrush().pattern()) { + HGTRACE(("fillPath(pattern)\n")); notImplemented(); - else if (m_state.fillBrush().gradient()) { - m_view->SetDrawingMode(B_OP_ALPHA); + } else if (m_state.fillBrush().gradient()) { + HGTRACE(("fillPath(gradient)\n")); const BGradient& gradient = m_state.fillBrush().gradient()->getHaikuGradient(); - m_view->FillShape(path.platformPath(), gradient); + m_painter->FillShape(path.platformPath(), gradient); } else { - if (m_view->HighColor().alpha < 255) - m_view->SetDrawingMode(B_OP_ALPHA); - - m_view->FillShape(path.platformPath(), B_SOLID_LOW); + HGTRACE(("fillPath(else)\n")); + m_painter->SetHighColor(m_state.fillBrush().color()); + m_painter->FillShape(path.platformPath(), B_SOLID_HIGH); } - - m_view->SetDrawingMode(mode); + m_painter->PopState(); + pathBitmap->RemoveChild(m_painter); + + BlendModeGuard guard(m_view); + m_view->SetDrawingMode(B_OP_ALPHA); + m_view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + getCTM(); + // FIXME: rect has negative coordinates so it writes all over memory + m_view->PushState(); + m_view->DrawBitmap(pathBitmap, pathBounds); + m_view->PopState(); + pathBitmap->Unlock(); + delete pathBitmap; } void GraphicsContextHaiku::clip(const FloatRect& rect) @@ -341,14 +461,25 @@ void GraphicsContextHaiku::clipPath(const Path& path, WindRule windRule) m_view->SetFillRule(fillRule); } -void GraphicsContextHaiku::clipToImageBuffer(WebCore::ImageBuffer&, WebCore::FloatRect const&) +void GraphicsContextHaiku::clipToImageBuffer(WebCore::ImageBuffer& imageBuffer, WebCore::FloatRect const& destRect) { - notImplemented(); + HGTRACEX(("clipToImageBuffer [%f:%f] [%f:%f]\n", destRect.x(), destRect.y(), destRect.width(), destRect.height())); + auto nativeImage = imageBuffer.createNativeImageReference(); + if(!nativeImage) + return; + + BBitmap* bmp = nativeImage->platformImage().get(); + + BlendModeGuard guard(m_view); + m_view->SetDrawingMode(B_OP_ALPHA); + m_view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + m_view->DrawBitmapAsync(bmp, BRect(destRect), BRect(destRect)); } void GraphicsContextHaiku::resetClip() { - notImplemented(); + HGTRACEX(("resetClip\n")); + m_view->ClipToRect(m_view->Bounds()); } @@ -364,32 +495,11 @@ void GraphicsContextHaiku::drawBitmap(BBitmap* image, const WebCore::FloatSize& const FloatRect& tileRect, const AffineTransform&, const FloatPoint& phase, const FloatSize& spacing, const ImagePaintingOptions&) { - HGTRACE(("drawBitmap: (--todo print values)\n")); + HGTRACEX(("drawBitmap: (--todo print values)\n")); if (!image->IsValid()) // If the image hasn't fully loaded. return; - // Figure out if the image has any alpha transparency, we can use faster drawing if not - bool hasAlpha = false; - - uint8* bits = reinterpret_cast(image->Bits()); - uint32 width = image->Bounds().IntegerWidth() + 1; - uint32 height = image->Bounds().IntegerHeight() + 1; - - uint32 bytesPerRow = image->BytesPerRow(); - for (uint32 y = 0; y < height && !hasAlpha; y++) { - uint8* p = bits; - for (uint32 x = 0; x < width && !hasAlpha; x++) { - hasAlpha = p[3] < 255; - p += 4; - } - bits += bytesPerRow; - } - m_view->PushState(); - if (hasAlpha) - m_view->SetDrawingMode(B_OP_ALPHA); - else - m_view->SetDrawingMode(B_OP_COPY); clip(enclosingIntRect(destRect)); float phaseOffsetX = destRect.x() - phase.x(); @@ -428,11 +538,9 @@ void GraphicsContextHaiku::drawFocusRing(const Path& path, float width, const Co // look good. width = 1; - m_view->PushState(); m_view->SetHighColor(color); m_view->SetPenSize(width); m_view->StrokeShape(path.platformPath(), B_SOLID_HIGH); - m_view->PopState(); } void GraphicsContextHaiku::drawFocusRing(const Vector& rects, float /*offset*/, float width, const Color& color) @@ -445,8 +553,6 @@ void GraphicsContextHaiku::drawFocusRing(const Vector& rects, float / if (rectCount <= 0) return; - m_view->PushState(); - // GTK forces this to 2, we use 1. A focus ring several pixels thick doesn't // look good. // FIXME this still draws a focus ring that looks not so good on "details" @@ -458,8 +564,6 @@ void GraphicsContextHaiku::drawFocusRing(const Vector& rects, float / // FIXME: maybe we should implement this with BShape? for (unsigned i = 0; i < rectCount; ++i) m_view->StrokeRect(rects[i], B_SOLID_HIGH); - - m_view->PopState(); } void GraphicsContextHaiku::drawLinesForText(const FloatPoint& point, @@ -503,11 +607,10 @@ void GraphicsContextHaiku::drawDotsForDocumentMarker(WebCore::FloatRect const&, void GraphicsContextHaiku::clearRect(const FloatRect& rect) { HGTRACE(("clearRect: [%f:%f] [%f:%f]\n", rect.x(), rect.y(), rect.width(), rect.height())); - m_view->PushState(); m_view->SetHighColor(0, 0, 0, 0); m_view->SetDrawingMode(B_OP_COPY); m_view->FillRect(rect); - m_view->PopState(); + m_view->SetDrawingMode(B_OP_ALPHA); } void GraphicsContextHaiku::setLineCap(LineCap lineCap) @@ -563,8 +666,8 @@ void GraphicsContextHaiku::setMiterLimit(float limit) AffineTransform GraphicsContextHaiku::getCTM(IncludeDeviceScale) const { - HGTRACE(("getCTM: no values used\n")); BAffineTransform t = m_view->Transform(); + HGTRACE(("getCTM: out[%f %f %f %f %f %f]\n", t.sx, t.shy, t.shx, t.sy, t.tx, t.ty)); // TODO: we actually need to use the combined transform here? AffineTransform matrix(t.sx, t.shy, t.shx, t.sy, t.tx, t.ty); return matrix; @@ -610,22 +713,34 @@ void GraphicsContextHaiku::setCTM(const AffineTransform& transform) void GraphicsContextHaiku::didUpdateState(GraphicsContextState& state) { - HGTRACE(("didUpdateState: (--todo print values)\n")); + if(state.changes().isEmpty()) { + state.didApplyChanges(); + return; + } + + TextStream ts; + ts << "didUpdateState "; + state.dump(ts); + HGTRACEX(("%s\n", ts.release().ascii().data())); #if 0 - StrokeGradientChange = 1 << 0, - StrokePatternChange = 1 << 1, - FillGradientChange // Handled directly in drawing operations - FillPatternChange = 1 << 3, + FillBrush = 1 << 0, + FillRule = 1 << 1, + + StrokeBrush = 1 << 2, + StrokeThickness = 1 << 3, + StrokeStyle = 1 << 4, + + Alpha = 1 << 8, #endif - if (state.changes().contains(GraphicsContextState::Change::StrokeThickness)) + if (state.changes().contains(GraphicsContextState::Change::StrokeThickness)) { m_view->SetPenSize(state.strokeThickness()); - if (state.changes().contains(GraphicsContextState::Change::StrokeBrush) - || state.changes().contains(GraphicsContextState::Change::Alpha)) { + } + if (state.changes().contains(GraphicsContextState::Change::StrokeBrush)) { rgb_color color = state.strokeBrush().color(); // FIXME the alpha is only applied to plain colors, not bitmaps, gradients, // or anything else. Support should be moved to app_server using the trick // mentionned here: http://permalink.gmane.org/gmane.comp.graphics.agg/2241 - color.alpha *= state.alpha(); + //color.alpha *= state.alpha(); m_view->SetHighColor(color); } if (state.changes().contains(GraphicsContextState::Change::StrokeStyle)) { @@ -653,23 +768,36 @@ void GraphicsContextHaiku::didUpdateState(GraphicsContextState& state) break; } } - if (state.changes().contains(GraphicsContextState::Change::FillBrush) - || state.changes().contains(GraphicsContextState::Change::Alpha)) { + if (state.changes().contains(GraphicsContextState::Change::FillBrush)) { rgb_color color = state.fillBrush().color(); // FIXME the alpha is only applied to plain colors, not bitmaps, gradients, // or anything else. Support should be moved to app_server using the trick // mentionned here: http://permalink.gmane.org/gmane.comp.graphics.agg/2241 - color.alpha *= state.alpha(); + //color.alpha *= state.alpha(); m_view->SetLowColor(color); } if (state.changes().contains(GraphicsContextState::Change::FillRule)) m_view->SetFillRule(fillRule() == WindRule::NonZero ? B_NONZERO : B_EVEN_ODD); #if 0 - ShadowChange = 1 << 9, - ShadowsIgnoreTransformsChange = 1 << 10, - AlphaChange = 1 << 11, + CompositeMode = 1 << 5, + DropShadow = 1 << 6, + Style = 1 << 7, #endif + if (state.changes().contains(GraphicsContextState::Change::Alpha)) { + rgb_color stroke = m_view->HighColor(); + rgb_color fill = m_view->LowColor(); + stroke.alpha = static_cast(255 * state.alpha()); + fill.alpha = static_cast(255 * state.alpha()); + m_view->SetHighColor(stroke); + m_view->SetLowColor(fill); + } + if (state.changes().contains(GraphicsContextState::Change::DropShadow)) { + /*drawing_mode mode = B_OP_ALPHA; + alpha_function blending_mode = B_ALPHA_COMPOSITE_SOURCE_IN; + m_view->SetDrawingMode(mode); + m_view->SetBlendingMode(B_PIXEL_ALPHA, blending_mode);*/ + } if (state.changes().contains(GraphicsContextState::Change::CompositeMode)) { drawing_mode mode = B_OP_ALPHA; alpha_function blending_mode = B_ALPHA_COMPOSITE; @@ -714,26 +842,24 @@ void GraphicsContextHaiku::didUpdateState(GraphicsContextState& state) blending_mode = B_ALPHA_COMPOSITE_XOR; break; case CompositeOperator::Copy: - mode = B_OP_COPY; + blending_mode = B_ALPHA_COMPOSITE; break; default: fprintf(stderr, "GraphicsContext::setCompositeOperation: Unsupported composite operation %s\n", compositeOperatorName(compositeMode().operation, compositeMode().blendMode).utf8().data()); } m_view->SetDrawingMode(mode); - - if (mode == B_OP_ALPHA) - m_view->SetBlendingMode(B_PIXEL_ALPHA, blending_mode); + m_view->SetBlendingMode(B_PIXEL_ALPHA, blending_mode); } #if 0 - BlendModeChange = 1 << 13, - TextDrawingModeChange = 1 << 14, - ShouldAntialiasChange = 1 << 15, - ShouldSmoothFontsChange = 1 << 16, - ShouldSubpixelQuantizeFontsChange = 1 << 17, - DrawLuminanceMaskChange = 1 << 18, - ImageInterpolationQualityChange // Handled in drawNativeImage - UseDarkAppearanceChange = 1 << 20, + TextDrawingMode = 1 << 9, + ImageInterpolationQuality = 1 << 10, + + ShouldAntialias = 1 << 11, + ShouldSmoothFonts = 1 << 12, + ShouldSubpixelQuantizeFonts = 1 << 13, + ShadowsIgnoreTransforms = 1 << 14, + DrawLuminanceMask = 1 << 15, #endif state.didApplyChanges(); @@ -761,6 +887,7 @@ void GraphicsContextHaiku::beginTransparencyLayer(float opacity) { HGTRACE(("beginTransparencyLayer: %f\n", opacity)); GraphicsContext::beginTransparencyLayer(opacity); + save(GraphicsContextState::Purpose::TransparencyLayer); m_view->BeginLayer(static_cast(opacity * 255.0)); } @@ -769,6 +896,7 @@ void GraphicsContextHaiku::endTransparencyLayer() HGTRACE(("endTransparencyLayer: no values\n")); GraphicsContext::endTransparencyLayer(); m_view->EndLayer(); + restore(GraphicsContextState::Purpose::TransparencyLayer); } IntRect GraphicsContextHaiku::clipBounds() const diff --git a/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.h b/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.h index 2179ced048657..13fe2b8827a40 100644 --- a/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.h +++ b/Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.h @@ -58,6 +58,7 @@ class GraphicsContextHaiku: public GraphicsContext { void fillRect(const FloatRect&, const Color&) override; void fillRect(const WebCore::FloatRect&, WebCore::Gradient&, const WebCore::AffineTransform&, RequiresClipToRect) override; void fillRoundedRectImpl(const FloatRoundedRect&, const Color&) override; + void fillRectWithRoundedHole(const FloatRect&, const FloatRoundedRect& roundedHoleRect, const Color& color); void clearRect(const FloatRect&) override; void strokeRect(const FloatRect&, float lineWidth) override; void setLineCap(LineCap) override; @@ -87,12 +88,14 @@ class GraphicsContextHaiku: public GraphicsContext { void endTransparencyLayer() override; IntRect clipBounds() const override; - void save(GraphicsContextState::Purpose) override; - void restore(GraphicsContextState::Purpose) override; + void save(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) override; + void restore(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) override; void drawBitmap(BBitmap*, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& = { }); void drawBitmap(BBitmap*, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, const ImagePaintingOptions& = { }); BView* m_view; + BView* m_painter; + BBitmap* m_fillBitmap; pattern m_strokeStyle; }; diff --git a/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp index 18ee558ff7073..c7b968124ee82 100644 --- a/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp +++ b/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp @@ -156,13 +156,13 @@ GraphicsContext& ImageBufferHaikuSurfaceBackend::context() void ImageBufferHaikuSurfaceBackend::getPixelBuffer( const IntRect& srcRect, PixelBuffer& destination) { - return ImageBufferBackend::getPixelBuffer(srcRect, std::span((const unsigned char*)m_data.m_image->Bits(), m_data.m_image->BitsLength()), destination); + return ImageBufferBackend::getPixelBuffer(srcRect, std::span(reinterpret_cast(m_data.m_image->Bits()), m_data.m_image->BitsLength()), destination); } void ImageBufferHaikuSurfaceBackend::putPixelBuffer(const PixelBufferSourceView& imageData, const IntRect& sourceRect, const IntPoint& destPoint, AlphaPremultiplication premultiplication) { ImageBufferBackend::putPixelBuffer(imageData, sourceRect, destPoint, premultiplication, - std::span((unsigned char*)m_data.m_image->Bits(), m_data.m_image->BitsLength())); + std::span(reinterpret_cast(m_data.m_image->Bits()), m_data.m_image->BitsLength())); } unsigned ImageBufferHaikuSurfaceBackend::bytesPerRow() const diff --git a/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp b/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp index 5a0162630fcc6..1d6aa461d63dc 100644 --- a/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp +++ b/Source/WebCore/platform/graphics/haiku/PathHaiku.cpp @@ -253,69 +253,6 @@ bool PathHaiku::strokeContains(const FloatPoint& point, const Functionx += m_size.width(); - point->y += m_size.height(); - return B_OK; - } - - virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts) - { - while (lineCount--) { - linePts->x += m_size.width(); - linePts->y += m_size.height(); - linePts++; - } - return B_OK; - } - - virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts) - { - while (bezierCount--) { - bezierPts[0].x += m_size.width(); - bezierPts[0].y += m_size.height(); - bezierPts[1].x += m_size.width(); - bezierPts[1].y += m_size.height(); - bezierPts[2].x += m_size.width(); - bezierPts[2].y += m_size.height(); - bezierPts += 3; - } - return B_OK; - } - - virtual status_t IterateArcTo(float& rx, float& ry, - float& angle, bool largeArc, bool counterClockWise, BPoint& point) - { - point.x += m_size.width(); - point.y += m_size.height(); - - return B_OK; - } - - virtual status_t IterateClose() - { - return B_OK; - } - - private: - const FloatSize& m_size; - } translateIterator(size); - - translateIterator.Iterate(m_path); -} -#endif - FloatRect PathHaiku::boundingRect() const { return m_platformPath.Bounds(); @@ -441,6 +378,7 @@ void PathHaiku::add(PathArcTo arcTo) void PathHaiku::addPath(const PathHaiku&, const AffineTransform&) { // FIXME: This should probably be very similar to Path::transform. + printf("FIXME addPath notImplemented()"); notImplemented(); } @@ -507,12 +445,6 @@ void PathHaiku::add(PathRoundedRect roundedRect) const FloatSize& bottomLeft = roundRect.radii().bottomLeft(); const FloatSize& bottomRight = roundRect.radii().bottomRight(); -#if 0 - // FIXME needs support for Composite SourceIn. - if (hasShadow()) - shadowBlur().drawRectShadow(this, rect, FloatRoundedRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); -#endif - BPoint points[3]; const float kRadiusBezierScale = 1.0f - 0.5522847498f; // 1 - (sqrt(2) - 1) * 4 / 3 @@ -557,12 +489,6 @@ void PathHaiku::add(PathContinuousRoundedRect roundedRect) const FloatRect& rect = roundedRect.rect; const FloatSize& corner = { roundedRect.cornerWidth, roundedRect.cornerHeight }; -#if 0 - // FIXME needs support for Composite SourceIn. - if (hasShadow()) - shadowBlur().drawRectShadow(this, rect, FloatRoundedRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); -#endif - BPoint points[3]; const float kRadiusBezierScale = 1.0f - 0.5522847498f; // 1 - (sqrt(2) - 1) * 4 / 3 @@ -656,13 +582,6 @@ void PathHaiku::add(PathEllipseInRect ellipseInRect) m_platformPath.Close(); } -#if 0 -void Path::clear() -{ - m_path->Clear(); -} -#endif - void PathHaiku::applySegments(const PathSegmentApplier& applier) const {