diff --git a/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index 47254e892b..832aa0bcac 100644 --- a/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -1438,17 +1438,17 @@ public: Ptr clipToPath (const Path& p, const AffineTransform& transform) { - return Ptr (new ClipRegion_EdgeTable (clip))->clipToPath (p, transform); + return toEdgeTable()->clipToPath (p, transform); } Ptr clipToEdgeTable (const EdgeTable& et) { - return Ptr (new ClipRegion_EdgeTable (clip))->clipToEdgeTable (et); + return toEdgeTable()->clipToEdgeTable (et); } Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const bool betterQuality) { - return Ptr (new ClipRegion_EdgeTable (clip))->clipToImageAlpha (image, transform, betterQuality); + return toEdgeTable()->clipToImageAlpha (image, transform, betterQuality); } Ptr translated (const Point& delta) @@ -1594,7 +1594,7 @@ private: class SubRectangleIteratorFloat { public: - SubRectangleIteratorFloat (const RectangleList& clip_, const Rectangle& area_) + SubRectangleIteratorFloat (const RectangleList& clip_, const Rectangle& area_) noexcept : clip (clip_), area (area_) { } @@ -1602,66 +1602,7 @@ private: template void iterate (Renderer& r) const noexcept { - int left = roundToInt (area.getX() * 256.0f); - int top = roundToInt (area.getY() * 256.0f); - int right = roundToInt (area.getRight() * 256.0f); - int bottom = roundToInt (area.getBottom() * 256.0f); - - int totalTop, totalLeft, totalBottom, totalRight; - int topAlpha, leftAlpha, bottomAlpha, rightAlpha; - - if ((top >> 8) == (bottom >> 8)) - { - topAlpha = bottom - top; - bottomAlpha = 0; - totalTop = top >> 8; - totalBottom = bottom = top = totalTop + 1; - } - else - { - if ((top & 255) == 0) - { - topAlpha = 0; - top = totalTop = (top >> 8); - } - else - { - topAlpha = 255 - (top & 255); - totalTop = (top >> 8); - top = totalTop + 1; - } - - bottomAlpha = bottom & 255; - bottom >>= 8; - totalBottom = bottom + (bottomAlpha != 0 ? 1 : 0); - } - - if ((left >> 8) == (right >> 8)) - { - leftAlpha = right - left; - rightAlpha = 0; - totalLeft = (left >> 8); - totalRight = right = left = totalLeft + 1; - } - else - { - if ((left & 255) == 0) - { - leftAlpha = 0; - left = totalLeft = (left >> 8); - } - else - { - leftAlpha = 255 - (left & 255); - totalLeft = (left >> 8); - left = totalLeft + 1; - } - - rightAlpha = right & 255; - right >>= 8; - totalRight = right + (rightAlpha != 0 ? 1 : 0); - } - + const RenderingHelpers::FloatRectangleRasterisingInfo f (area); RectangleList::Iterator iter (clip); while (iter.next()) @@ -1671,62 +1612,62 @@ private: const int clipTop = iter.getRectangle()->getY(); const int clipBottom = iter.getRectangle()->getBottom(); - if (totalBottom > clipTop && totalTop < clipBottom && totalRight > clipLeft && totalLeft < clipRight) + if (f.totalBottom > clipTop && f.totalTop < clipBottom && f.totalRight > clipLeft && f.totalLeft < clipRight) { - if (right - left == 1 && leftAlpha + rightAlpha == 0) // special case for 1-pix vertical lines + if (f.isOnePixelWide()) { - if (topAlpha != 0 && totalTop >= clipTop) + if (f.topAlpha != 0 && f.totalTop >= clipTop) { - r.setEdgeTableYPos (totalTop); - r.handleEdgeTablePixel (left, topAlpha); + r.setEdgeTableYPos (f.totalTop); + r.handleEdgeTablePixel (f.left, f.topAlpha); } - const int endY = jmin (bottom, clipBottom); - for (int y = jmax (clipTop, top); y < endY; ++y) + const int endY = jmin (f.bottom, clipBottom); + for (int y = jmax (clipTop, f.top); y < endY; ++y) { r.setEdgeTableYPos (y); - r.handleEdgeTablePixelFull (left); + r.handleEdgeTablePixelFull (f.left); } - if (bottomAlpha != 0 && bottom < clipBottom) + if (f.bottomAlpha != 0 && f.bottom < clipBottom) { - r.setEdgeTableYPos (bottom); - r.handleEdgeTablePixel (left, bottomAlpha); + r.setEdgeTableYPos (f.bottom); + r.handleEdgeTablePixel (f.left, f.bottomAlpha); } } else { - const int clippedLeft = jmax (left, clipLeft); - const int clippedWidth = jmin (right, clipRight) - clippedLeft; - const bool doLeftAlpha = leftAlpha != 0 && totalLeft >= clipLeft; - const bool doRightAlpha = rightAlpha != 0 && right < clipRight; + const int clippedLeft = jmax (f.left, clipLeft); + const int clippedWidth = jmin (f.right, clipRight) - clippedLeft; + const bool doLeftAlpha = f.leftAlpha != 0 && f.totalLeft >= clipLeft; + const bool doRightAlpha = f.rightAlpha != 0 && f.right < clipRight; - if (topAlpha != 0 && totalTop >= clipTop) + if (f.topAlpha != 0 && f.totalTop >= clipTop) { - r.setEdgeTableYPos (totalTop); + r.setEdgeTableYPos (f.totalTop); - if (doLeftAlpha) r.handleEdgeTablePixel (totalLeft, (leftAlpha * topAlpha) >> 8); - if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, topAlpha); - if (doRightAlpha) r.handleEdgeTablePixel (right, (rightAlpha * topAlpha) >> 8); + if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.getTopLeftCornerAlpha()); + if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, f.topAlpha); + if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.getTopRightCornerAlpha()); } - const int endY = jmin (bottom, clipBottom); - for (int y = jmax (clipTop, top); y < endY; ++y) + const int endY = jmin (f.bottom, clipBottom); + for (int y = jmax (clipTop, f.top); y < endY; ++y) { r.setEdgeTableYPos (y); - if (doLeftAlpha) r.handleEdgeTablePixel (totalLeft, leftAlpha); + if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.leftAlpha); if (clippedWidth > 0) r.handleEdgeTableLineFull (clippedLeft, clippedWidth); - if (doRightAlpha) r.handleEdgeTablePixel (right, rightAlpha); + if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.rightAlpha); } - if (bottomAlpha != 0 && bottom < clipBottom) + if (f.bottomAlpha != 0 && f.bottom < clipBottom) { - r.setEdgeTableYPos (bottom); + r.setEdgeTableYPos (f.bottom); - if (doLeftAlpha) r.handleEdgeTablePixel (totalLeft, (leftAlpha * bottomAlpha) >> 8); - if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, bottomAlpha); - if (doRightAlpha) r.handleEdgeTablePixel (right, (rightAlpha * bottomAlpha) >> 8); + if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.getBottomLeftCornerAlpha()); + if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, f.bottomAlpha); + if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.getBottomRightCornerAlpha()); } } } @@ -1740,6 +1681,8 @@ private: JUCE_DECLARE_NON_COPYABLE (SubRectangleIteratorFloat); }; + inline Ptr toEdgeTable() const { return new ClipRegion_EdgeTable (clip); } + ClipRegion_RectangleList& operator= (const ClipRegion_RectangleList&); }; diff --git a/modules/juce_graphics/native/juce_RenderingHelpers.h b/modules/juce_graphics/native/juce_RenderingHelpers.h index 95ca7960fd..f230db2f47 100644 --- a/modules/juce_graphics/native/juce_RenderingHelpers.h +++ b/modules/juce_graphics/native/juce_RenderingHelpers.h @@ -232,12 +232,12 @@ public: inline StateObjectType* operator->() const noexcept { return currentState; } inline StateObjectType& operator*() const noexcept { return *currentState; } - + void save() { stack.add (new StateObjectType (*currentState)); } - + void restore() { StateObjectType* const top = stack.getLast(); @@ -252,7 +252,7 @@ public: jassertfalse; // trying to pop with an empty stack! } } - + void beginTransparencyLayer (float opacity) { save(); @@ -272,7 +272,95 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedStateStack); }; - + +//============================================================================== +// Calculates the alpha values and positions for rendering the edges of a non-pixel +// aligned rectangle. +struct FloatRectangleRasterisingInfo +{ + FloatRectangleRasterisingInfo (const Rectangle& area) + : left (roundToInt (256.0f * area.getX())), + top (roundToInt (256.0f * area.getY())), + right (roundToInt (256.0f * area.getRight())), + bottom (roundToInt (256.0f * area.getBottom())) + { + if ((top >> 8) == (bottom >> 8)) + { + topAlpha = bottom - top; + bottomAlpha = 0; + totalTop = top >> 8; + totalBottom = bottom = top = totalTop + 1; + } + else + { + if ((top & 255) == 0) + { + topAlpha = 0; + top = totalTop = (top >> 8); + } + else + { + topAlpha = 255 - (top & 255); + totalTop = (top >> 8); + top = totalTop + 1; + } + + bottomAlpha = bottom & 255; + bottom >>= 8; + totalBottom = bottom + (bottomAlpha != 0 ? 1 : 0); + } + + if ((left >> 8) == (right >> 8)) + { + leftAlpha = right - left; + rightAlpha = 0; + totalLeft = (left >> 8); + totalRight = right = left = totalLeft + 1; + } + else + { + if ((left & 255) == 0) + { + leftAlpha = 0; + left = totalLeft = (left >> 8); + } + else + { + leftAlpha = 255 - (left & 255); + totalLeft = (left >> 8); + left = totalLeft + 1; + } + + rightAlpha = right & 255; + right >>= 8; + totalRight = right + (rightAlpha != 0 ? 1 : 0); + } + } + + template + void iterate (Callback& callback) const + { + if (topAlpha != 0) callback (totalLeft, totalTop, totalRight - totalLeft, 1, topAlpha); + if (bottomAlpha != 0) callback (totalLeft, bottom, totalRight - totalLeft, 1, bottomAlpha); + if (leftAlpha != 0) callback (totalLeft, totalTop, 1, totalBottom - totalTop, leftAlpha); + if (rightAlpha != 0) callback (right, totalTop, 1, totalBottom - totalTop, rightAlpha); + + callback (left, top, 1, bottom - top, 255); + } + + inline bool isOnePixelWide() const noexcept { return right - left == 1 && leftAlpha + rightAlpha == 0; } + + inline int getTopLeftCornerAlpha() const noexcept { return (topAlpha * leftAlpha) >> 8; } + inline int getTopRightCornerAlpha() const noexcept { return (topAlpha * rightAlpha) >> 8; } + inline int getBottomLeftCornerAlpha() const noexcept { return (bottomAlpha * leftAlpha) >> 8; } + inline int getBottomRightCornerAlpha() const noexcept { return (bottomAlpha * rightAlpha) >> 8; } + + //============================================================================== + int left, top, right, bottom; // bounds of the solid central area, excluding anti-aliased edges + int totalTop, totalLeft, totalBottom, totalRight; // bounds of the total area, including edges + int topAlpha, leftAlpha, bottomAlpha, rightAlpha; // alpha of each anti-aliased edge +}; + } #endif // __JUCE_RENDERINGHELPERS_JUCEHEADER__ diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index f3d603e7a5..18f3bfb0de 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -202,7 +202,7 @@ public: } #endif - static const Identifier getColourPropertyId (const int colourId) + static Identifier getColourPropertyId (const int colourId) { String s; s.preallocateBytes (32); @@ -302,7 +302,7 @@ public: return convertFromDistantParentSpace (topLevelComp, *target, p); } - static const Rectangle getUnclippedArea (const Component& comp) + static Rectangle getUnclippedArea (const Component& comp) { Rectangle r (comp.getLocalBounds()); @@ -370,7 +370,7 @@ public: } } - static const Rectangle getParentOrMainMonitorBounds (const Component& comp) + static Rectangle getParentOrMainMonitorBounds (const Component& comp) { return comp.getParentComponent() != nullptr ? comp.getParentComponent()->getLocalBounds() : Desktop::getInstance().getMainMonitorArea(); @@ -1219,9 +1219,9 @@ bool Component::hitTest (int x, int y) if (flags.allowChildMouseClicksFlag) { - for (int i = getNumChildComponents(); --i >= 0;) + for (int i = childComponentList.size(); --i >= 0;) { - Component& child = *getChildComponent (i); + Component& child = *childComponentList.getUnchecked (i); if (child.isVisible() && ComponentHelpers::hitTest (child, ComponentHelpers::convertFromParentSpace (child, Point (x, y))))