mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-11 23:54:18 +00:00
Improvements to path rendering and fix for PathStrokeType generating incorrect paths for some shapes. Added OSX10.4 compatibility for new new typeface classes.
This commit is contained in:
parent
dc83bf01e1
commit
ca727ec2bb
12 changed files with 795 additions and 355 deletions
|
|
@ -146,7 +146,7 @@ public:
|
|||
true); // resize the components' heights as well as widths
|
||||
|
||||
// now lay out the text box and the controls below it..
|
||||
int x = verticalLayout.getItemCurrentPosition (2);
|
||||
int x = verticalLayout.getItemCurrentPosition (2) + 4;
|
||||
textBox->setBounds (x, 0, getWidth() - x, getHeight() - 110);
|
||||
x += 70;
|
||||
sizeSlider->setBounds (x, getHeight() - 106, getWidth() - x, 22);
|
||||
|
|
|
|||
|
|
@ -78825,13 +78825,121 @@ BEGIN_JUCE_NAMESPACE
|
|||
|
||||
const int juce_edgeTableDefaultEdgesPerLine = 32;
|
||||
|
||||
EdgeTable::EdgeTable (const int top_, const int height_) throw()
|
||||
EdgeTable::EdgeTable (const int top_, const int height_,
|
||||
const Path& path, const AffineTransform& transform) throw()
|
||||
: top (top_),
|
||||
height (height_),
|
||||
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
|
||||
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
|
||||
{
|
||||
table = (int*) juce_calloc (height * lineStrideElements * sizeof (int));
|
||||
table = (int*) juce_malloc (height_ * lineStrideElements * sizeof (int));
|
||||
int* t = table;
|
||||
for (int i = height_; --i >= 0;)
|
||||
{
|
||||
*t = 0;
|
||||
t += lineStrideElements;
|
||||
}
|
||||
|
||||
const int topLimit = top << 8;
|
||||
const int bottomLimit = height << 8;
|
||||
PathFlatteningIterator iter (path, transform);
|
||||
|
||||
while (iter.next())
|
||||
{
|
||||
int y1 = roundFloatToInt (iter.y1 * 256.0f);
|
||||
int y2 = roundFloatToInt (iter.y2 * 256.0f);
|
||||
|
||||
if (y1 != y2)
|
||||
{
|
||||
y1 -= topLimit;
|
||||
y2 -= topLimit;
|
||||
|
||||
const double startX = 256.0f * iter.x1;
|
||||
const int startY = y1;
|
||||
const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
|
||||
int winding = -1;
|
||||
|
||||
if (y1 > y2)
|
||||
{
|
||||
swapVariables (y1, y2);
|
||||
winding = 1;
|
||||
}
|
||||
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
|
||||
if (y2 > bottomLimit)
|
||||
y2 = bottomLimit;
|
||||
|
||||
const int stepSize = jlimit (1, 256, 256 / (1 + (int) fabs (multiplier)));
|
||||
|
||||
while (y1 < y2)
|
||||
{
|
||||
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
|
||||
|
||||
addEdgePoint (roundDoubleToInt (startX + multiplier * (y1 - startY)),
|
||||
y1 >> 8, winding * step);
|
||||
|
||||
y1 += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! path.isUsingNonZeroWinding())
|
||||
{
|
||||
int* lineStart = table;
|
||||
|
||||
for (int i = height; --i >= 0;)
|
||||
{
|
||||
int* line = lineStart;
|
||||
lineStart += lineStrideElements;
|
||||
int num = *line;
|
||||
int level = 0;
|
||||
int lastCorrected = 0;
|
||||
|
||||
while (--num >= 0)
|
||||
{
|
||||
line += 2;
|
||||
level += *line;
|
||||
int corrected = abs (level);
|
||||
if (corrected >> 8)
|
||||
{
|
||||
corrected &= 511;
|
||||
if (corrected >> 8)
|
||||
corrected = 511 - corrected;
|
||||
}
|
||||
|
||||
*line = corrected - lastCorrected;
|
||||
lastCorrected = corrected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw()
|
||||
: top (rectangleToAdd.getY()),
|
||||
height (jmax (1, rectangleToAdd.getHeight())),
|
||||
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
|
||||
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
|
||||
{
|
||||
jassert (! rectangleToAdd.isEmpty());
|
||||
|
||||
table = (int*) juce_malloc (height * lineStrideElements * sizeof (int));
|
||||
*table = 0;
|
||||
|
||||
const int x1 = rectangleToAdd.getX();
|
||||
const int x2 = rectangleToAdd.getRight();
|
||||
|
||||
int* t = table;
|
||||
for (int i = rectangleToAdd.getHeight(); --i >= 0;)
|
||||
{
|
||||
t[0] = 2;
|
||||
t[1] = x1;
|
||||
t[2] = 256;
|
||||
t[3] = x2;
|
||||
t[4] = -256;
|
||||
t += lineStrideElements;
|
||||
}
|
||||
}
|
||||
|
||||
EdgeTable::EdgeTable (const EdgeTable& other) throw()
|
||||
|
|
@ -78936,94 +79044,47 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw
|
|||
lineStart[0]++;
|
||||
}
|
||||
|
||||
void EdgeTable::addPath (const Path& path, const AffineTransform& transform) throw()
|
||||
void EdgeTable::clearLineSection (const int y, int minX, int maxX) throw()
|
||||
{
|
||||
const int bottomLimit = height << 8;
|
||||
// int* line = table + lineStrideElements * y;
|
||||
|
||||
PathFlatteningIterator iter (path, transform);
|
||||
}
|
||||
|
||||
while (iter.next())
|
||||
void EdgeTable::clipToRectangle (const Rectangle& r) throw()
|
||||
{
|
||||
const int rectTop = jmax (0, r.getY() - top);
|
||||
const int rectBottom = jmin (height, r.getBottom() - top);
|
||||
|
||||
for (int i = rectTop - 1; --i >= 0;)
|
||||
table [lineStrideElements * i] = 0;
|
||||
|
||||
for (int i = rectBottom; i < height; ++i)
|
||||
table [lineStrideElements * i] = 0;
|
||||
|
||||
for (int i = rectTop; i < rectBottom; ++i)
|
||||
{
|
||||
int y1 = roundFloatToInt (iter.y1 * 256.0f) - (top << 8);
|
||||
int y2 = roundFloatToInt (iter.y2 * 256.0f) - (top << 8);
|
||||
|
||||
if (y1 != y2)
|
||||
{
|
||||
const int oldY1 = y1;
|
||||
const double x1 = 256.0 * iter.x1;
|
||||
const double x2 = 256.0 * iter.x2;
|
||||
const double multiplier = (x2 - x1) / (y2 - y1);
|
||||
int winding = -1;
|
||||
|
||||
if (y1 > y2)
|
||||
{
|
||||
swapVariables (y1, y2);
|
||||
winding = 1;
|
||||
}
|
||||
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
|
||||
if (y2 > bottomLimit)
|
||||
y2 = bottomLimit;
|
||||
|
||||
const int stepSize = jlimit (1, 256, 256 / (1 + abs ((int) multiplier)));
|
||||
|
||||
while (y1 < y2)
|
||||
{
|
||||
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
|
||||
|
||||
addEdgePoint (roundDoubleToInt (x1 + multiplier * (y1 - oldY1)),
|
||||
y1 >> 8, winding * step);
|
||||
|
||||
y1 += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! path.isUsingNonZeroWinding())
|
||||
{
|
||||
int* lineStart = table;
|
||||
|
||||
for (int i = height; --i >= 0;)
|
||||
{
|
||||
int* line = lineStart;
|
||||
lineStart += lineStrideElements;
|
||||
int num = *line;
|
||||
int level = 0;
|
||||
int lastCorrected = 0;
|
||||
|
||||
while (--num >= 0)
|
||||
{
|
||||
line += 2;
|
||||
level += *line;
|
||||
int corrected = abs (level);
|
||||
if (corrected >> 8)
|
||||
{
|
||||
corrected &= 511;
|
||||
if (corrected >> 8)
|
||||
corrected = 511 - corrected;
|
||||
}
|
||||
|
||||
*line = corrected - lastCorrected;
|
||||
lastCorrected = corrected;
|
||||
}
|
||||
}
|
||||
clearLineSection (i, -INT_MAX, r.getX());
|
||||
clearLineSection (i, r.getRight(), INT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
/*void EdgeTable::clipToRectangle (const Rectangle& r) throw()
|
||||
void EdgeTable::excludeRectangle (const Rectangle& r) throw()
|
||||
{
|
||||
const int rectTop = jmax (0, r.getY() - top);
|
||||
const int rectBottom = jmin (height, r.getBottom() - top);
|
||||
|
||||
for (int i = rectTop; i < rectBottom; ++i)
|
||||
clearLineSection (i, r.getX(), r.getRight());
|
||||
}
|
||||
|
||||
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
|
||||
{
|
||||
}
|
||||
|
||||
void EdgeTable::intersectWith (const EdgeTable& other)
|
||||
void EdgeTable::clipToImageAlpha (Image& image, int x, int y) throw()
|
||||
{
|
||||
}
|
||||
|
||||
void EdgeTable::generateFromImageAlpha (Image& image, int x, int y) throw()
|
||||
{
|
||||
}*/
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/********* End of inlined file: juce_EdgeTable.cpp *********/
|
||||
|
||||
|
|
@ -81995,8 +82056,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPath (int clipX, int clipY, in
|
|||
|
||||
if (getPathBounds (clipX, clipY, clipW, clipH, path, transform, cx, cy, cw, ch))
|
||||
{
|
||||
EdgeTable edgeTable (0, ch);
|
||||
edgeTable.addPath (path, transform.translated ((float) -cx, (float) -cy));
|
||||
EdgeTable edgeTable (0, ch, path, transform.translated ((float) -cx, (float) -cy));
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (cx, cy, cw, ch, stride, pixelStride);
|
||||
|
|
@ -82123,8 +82183,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPathWithImage (int x, int y, i
|
|||
{
|
||||
if (Rectangle::intersectRectangles (x, y, w, h, imageX, imageY, sourceImage.getWidth(), sourceImage.getHeight()))
|
||||
{
|
||||
EdgeTable edgeTable (0, h);
|
||||
edgeTable.addPath (path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
|
||||
EdgeTable edgeTable (0, h, path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (x, y, w, h, stride, pixelStride);
|
||||
|
|
@ -85928,17 +85987,21 @@ void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <fl
|
|||
|
||||
const float scale = font->height * font->horizontalScale;
|
||||
const int num = xOffsets.size();
|
||||
float* const x = &(xOffsets.getReference(0));
|
||||
|
||||
if (font->kerning != 0)
|
||||
if (num > 0)
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] = (x[i] + i * font->kerning) * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] *= scale;
|
||||
float* const x = &(xOffsets.getReference(0));
|
||||
|
||||
if (font->kerning != 0)
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] = (x[i] + i * font->kerning) * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86069,7 +86132,7 @@ public:
|
|||
|
||||
g.fillAlphaChannel (*bitmap [bitmapToUse],
|
||||
xOrigin [bitmapToUse] + (int) xFloor,
|
||||
yOrigin [bitmapToUse] + (int) floorf (y));
|
||||
yOrigin [bitmapToUse] + roundFloatToInt(y));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89983,8 +90046,8 @@ Image* Path::createMaskBitmap (const AffineTransform& transform,
|
|||
|
||||
Image* im = new Image (Image::SingleChannel, imagePosition.getWidth(), imagePosition.getHeight(), true);
|
||||
|
||||
EdgeTable edgeTable (0, imagePosition.getHeight());
|
||||
edgeTable.addPath (*this, transform.translated (-imagePosition.getX(), -imagePosition.getY()));
|
||||
EdgeTable edgeTable (0, imagePosition.getHeight(), *this,
|
||||
transform.translated (-imagePosition.getX(), -imagePosition.getY()));
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* const pixels = (uint8*) im->lockPixelDataReadWrite (0, 0, imagePosition.getWidth(), imagePosition.getHeight(), stride, pixelStride);
|
||||
|
|
@ -90473,20 +90536,47 @@ static void addEdgeAndJoint (Path& destPath,
|
|||
else
|
||||
{
|
||||
// curved joints
|
||||
float angle = atan2f (x2 - midX, y2 - midY);
|
||||
float angle1 = atan2f (x2 - midX, y2 - midY);
|
||||
float angle2 = atan2f (x3 - midX, y3 - midY);
|
||||
|
||||
while (angle < angle2 - 0.01f)
|
||||
angle2 -= float_Pi * 2.0f;
|
||||
const float angleIncrement = 0.1f;
|
||||
|
||||
destPath.lineTo (x2, y2);
|
||||
|
||||
while (angle > angle2)
|
||||
if (fabs (angle1 - angle2) > angleIncrement)
|
||||
{
|
||||
destPath.lineTo (midX + width * sinf (angle),
|
||||
midY + width * cosf (angle));
|
||||
if (angle2 > angle1 + float_Pi
|
||||
|| (angle2 < angle1 && angle2 >= angle1 - float_Pi))
|
||||
{
|
||||
if (angle2 > angle1)
|
||||
angle2 -= float_Pi * 2.0f;
|
||||
|
||||
angle -= 0.1f;
|
||||
jassert (angle1 <= angle2 + float_Pi);
|
||||
|
||||
angle1 -= angleIncrement;
|
||||
while (angle1 > angle2)
|
||||
{
|
||||
destPath.lineTo (midX + width * sinf (angle1),
|
||||
midY + width * cosf (angle1));
|
||||
|
||||
angle1 -= angleIncrement;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (angle1 > angle2)
|
||||
angle1 -= float_Pi * 2.0f;
|
||||
|
||||
jassert (angle1 >= angle2 - float_Pi);
|
||||
|
||||
angle1 += angleIncrement;
|
||||
while (angle1 < angle2)
|
||||
{
|
||||
destPath.lineTo (midX + width * sinf (angle1),
|
||||
midY + width * cosf (angle1));
|
||||
|
||||
angle1 += angleIncrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destPath.lineTo (x3, y3);
|
||||
|
|
@ -261922,6 +262012,17 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw()
|
|||
// compiled on its own).
|
||||
#if JUCE_INCLUDED_FILE
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define SUPPORT_10_4_FONTS 1
|
||||
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
@interface NSFont (PrivateHack)
|
||||
- (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
|
||||
@end
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
#endif
|
||||
|
||||
class MacTypeface : public Typeface
|
||||
{
|
||||
public:
|
||||
|
|
@ -261973,6 +262074,9 @@ public:
|
|||
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
#else
|
||||
nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
|
||||
|
||||
|
|
@ -262004,18 +262108,40 @@ public:
|
|||
renderingTransform.c = 0.15f;
|
||||
}
|
||||
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
|
||||
#endif
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
if (atsFont == 0)
|
||||
atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
|
||||
|
||||
fontRef = CGFontCreateWithPlatformFont ((void*) &atsFont);
|
||||
|
||||
const float totalHeight = fabsf ([nsFont ascender]) + fabsf([nsFont descender]);
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = 1024.0f / totalHeight;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
~MacTypeface()
|
||||
{
|
||||
[nsFont release];
|
||||
CGFontRelease (fontRef);
|
||||
|
||||
if (fontRef != 0)
|
||||
CGFontRelease (fontRef);
|
||||
|
||||
delete charToGlyphMapper;
|
||||
}
|
||||
|
||||
|
|
@ -262031,50 +262157,88 @@ public:
|
|||
|
||||
float getStringWidth (const String& text)
|
||||
{
|
||||
if (fontRef == 0)
|
||||
if (fontRef == 0 || text.isEmpty())
|
||||
return 0;
|
||||
|
||||
Array <int> glyphs (128);
|
||||
createGlyphsForString (text, glyphs);
|
||||
|
||||
if (glyphs.size() == 0)
|
||||
return 0;
|
||||
const int length = text.length();
|
||||
CGGlyph* const glyphs = createGlyphsForString (text, length);
|
||||
|
||||
int x = 0;
|
||||
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
|
||||
for (int i = 0; i < glyphs.size(); ++i)
|
||||
x += advances [i * 2];
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
|
||||
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
x += advances[i].width;
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int* const advances = (int*) juce_malloc (length * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
|
||||
for (int i = 0; i < length; ++i)
|
||||
x += advances[i];
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
|
||||
juce_free (glyphs);
|
||||
|
||||
juce_free (advances);
|
||||
return x * unitsToHeightScaleFactor;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets)
|
||||
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
|
||||
{
|
||||
if (fontRef == 0)
|
||||
return;
|
||||
|
||||
createGlyphsForString (text, glyphs);
|
||||
|
||||
xOffsets.add (0);
|
||||
if (glyphs.size() == 0)
|
||||
|
||||
if (fontRef == 0 || text.isEmpty())
|
||||
return;
|
||||
|
||||
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
|
||||
const int length = text.length();
|
||||
CGGlyph* const glyphs = createGlyphsForString (text, length);
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
|
||||
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
|
||||
|
||||
int x = 0;
|
||||
for (int i = 0; i < glyphs.size(); ++i)
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
x += advances [i * 2];
|
||||
x += advances[i].width;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int* const advances = (int*) juce_malloc (length * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
|
||||
{
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
x += advances [i];
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (glyphs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
juce_free (glyphs);
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
|
|
@ -262139,15 +262303,28 @@ private:
|
|||
AffineTransform pathTransform;
|
||||
#endif
|
||||
|
||||
void createGlyphsForString (const String& text, Array <int>& dest) throw()
|
||||
CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw()
|
||||
{
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length);
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]];
|
||||
|
||||
return (CGGlyph*) g;
|
||||
}
|
||||
#endif
|
||||
if (charToGlyphMapper == 0)
|
||||
charToGlyphMapper = new CharToGlyphMapper (fontRef);
|
||||
|
||||
const juce_wchar* t = (const juce_wchar*) text;
|
||||
CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length);
|
||||
|
||||
while (*t != 0)
|
||||
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
|
||||
for (int i = 0; i < length; ++i)
|
||||
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
// Reads a CGFontRef's character map table to convert unicode into glyph numbers
|
||||
|
|
@ -265578,6 +265755,17 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
|
|||
// compiled on its own).
|
||||
#if JUCE_INCLUDED_FILE
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define SUPPORT_10_4_FONTS 1
|
||||
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
@interface NSFont (PrivateHack)
|
||||
- (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
|
||||
@end
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
#endif
|
||||
|
||||
class MacTypeface : public Typeface
|
||||
{
|
||||
public:
|
||||
|
|
@ -265629,6 +265817,9 @@ public:
|
|||
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
#else
|
||||
nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
|
||||
|
||||
|
|
@ -265660,18 +265851,40 @@ public:
|
|||
renderingTransform.c = 0.15f;
|
||||
}
|
||||
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
|
||||
#endif
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
if (atsFont == 0)
|
||||
atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
|
||||
|
||||
fontRef = CGFontCreateWithPlatformFont ((void*) &atsFont);
|
||||
|
||||
const float totalHeight = fabsf ([nsFont ascender]) + fabsf([nsFont descender]);
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = 1024.0f / totalHeight;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
~MacTypeface()
|
||||
{
|
||||
[nsFont release];
|
||||
CGFontRelease (fontRef);
|
||||
|
||||
if (fontRef != 0)
|
||||
CGFontRelease (fontRef);
|
||||
|
||||
delete charToGlyphMapper;
|
||||
}
|
||||
|
||||
|
|
@ -265687,50 +265900,88 @@ public:
|
|||
|
||||
float getStringWidth (const String& text)
|
||||
{
|
||||
if (fontRef == 0)
|
||||
if (fontRef == 0 || text.isEmpty())
|
||||
return 0;
|
||||
|
||||
Array <int> glyphs (128);
|
||||
createGlyphsForString (text, glyphs);
|
||||
|
||||
if (glyphs.size() == 0)
|
||||
return 0;
|
||||
const int length = text.length();
|
||||
CGGlyph* const glyphs = createGlyphsForString (text, length);
|
||||
|
||||
int x = 0;
|
||||
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
|
||||
for (int i = 0; i < glyphs.size(); ++i)
|
||||
x += advances [i * 2];
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
|
||||
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
x += advances[i].width;
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int* const advances = (int*) juce_malloc (length * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
|
||||
for (int i = 0; i < length; ++i)
|
||||
x += advances[i];
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
|
||||
juce_free (glyphs);
|
||||
|
||||
juce_free (advances);
|
||||
return x * unitsToHeightScaleFactor;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets)
|
||||
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
|
||||
{
|
||||
if (fontRef == 0)
|
||||
return;
|
||||
|
||||
createGlyphsForString (text, glyphs);
|
||||
|
||||
xOffsets.add (0);
|
||||
if (glyphs.size() == 0)
|
||||
|
||||
if (fontRef == 0 || text.isEmpty())
|
||||
return;
|
||||
|
||||
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
|
||||
const int length = text.length();
|
||||
CGGlyph* const glyphs = createGlyphsForString (text, length);
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
|
||||
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
|
||||
|
||||
int x = 0;
|
||||
for (int i = 0; i < glyphs.size(); ++i)
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
x += advances [i * 2];
|
||||
x += advances[i].width;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int* const advances = (int*) juce_malloc (length * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
|
||||
{
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
x += advances [i];
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (glyphs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
juce_free (glyphs);
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
|
|
@ -265795,15 +266046,28 @@ private:
|
|||
AffineTransform pathTransform;
|
||||
#endif
|
||||
|
||||
void createGlyphsForString (const String& text, Array <int>& dest) throw()
|
||||
CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw()
|
||||
{
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length);
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]];
|
||||
|
||||
return (CGGlyph*) g;
|
||||
}
|
||||
#endif
|
||||
if (charToGlyphMapper == 0)
|
||||
charToGlyphMapper = new CharToGlyphMapper (fontRef);
|
||||
|
||||
const juce_wchar* t = (const juce_wchar*) text;
|
||||
CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length);
|
||||
|
||||
while (*t != 0)
|
||||
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
|
||||
for (int i = 0; i < length; ++i)
|
||||
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
// Reads a CGFontRef's character map table to convert unicode into glyph numbers
|
||||
|
|
@ -266268,7 +266532,7 @@ public:
|
|||
if (state->fontRef != 0)
|
||||
{
|
||||
CGGlyph g = glyphNumber;
|
||||
CGContextShowGlyphsAtPoint (context, x, flipHeight - y, &g, 1);
|
||||
CGContextShowGlyphsAtPoint (context, x, flipHeight - roundFloatToInt (y), &g, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17087,15 +17087,22 @@ class JUCE_API EdgeTable
|
|||
{
|
||||
public:
|
||||
|
||||
/** Creates an empty edge table ready to have paths added.
|
||||
/** Creates an edge table containing a path.
|
||||
|
||||
A table is created with a fixed vertical size, and only sections of paths
|
||||
which lie within their range will be added to the table.
|
||||
A table is created with a fixed vertical range, and only sections of the path
|
||||
which lie within this range will be added to the table.
|
||||
|
||||
@param y the lowest y co-ordinate that the table can contain
|
||||
@param y the top y co-ordinate that the table can contain
|
||||
@param height the number of horizontal lines it contains
|
||||
@param pathToAdd the path to add to the table
|
||||
@param transform a transform to apply to the path being added
|
||||
*/
|
||||
EdgeTable (const int y, const int height) throw();
|
||||
EdgeTable (const int y, const int height,
|
||||
const Path& pathToAdd, const AffineTransform& transform) throw();
|
||||
|
||||
/** Creates an edge table containing a rectangle.
|
||||
*/
|
||||
EdgeTable (const Rectangle& rectangleToAdd) throw();
|
||||
|
||||
/** Creates a copy of another edge table. */
|
||||
EdgeTable (const EdgeTable& other) throw();
|
||||
|
|
@ -17106,21 +17113,10 @@ public:
|
|||
/** Destructor. */
|
||||
~EdgeTable() throw();
|
||||
|
||||
/** Adds edges to the table for a path.
|
||||
|
||||
This will add horizontal lines to the edge table for any parts of the path
|
||||
which lie within the vertical bounds for which this table was created.
|
||||
|
||||
@param path the path to add
|
||||
@param transform an optional transform to apply to the path while it's
|
||||
being added
|
||||
*/
|
||||
void addPath (const Path& path,
|
||||
const AffineTransform& transform) throw();
|
||||
|
||||
/*void clipToRectangle (const Rectangle& r) throw();
|
||||
void intersectWith (const EdgeTable& other);
|
||||
void generateFromImageAlpha (Image& image, int x, int y) throw();*/
|
||||
void clipToRectangle (const Rectangle& r) throw();
|
||||
void excludeRectangle (const Rectangle& r) throw();
|
||||
void clipToEdgeTable (const EdgeTable& other);
|
||||
void clipToImageAlpha (Image& image, int x, int y) throw();
|
||||
|
||||
/** Reduces the amount of space the table has allocated.
|
||||
|
||||
|
|
@ -17208,7 +17204,12 @@ public:
|
|||
{
|
||||
levelAccumulator >>= 8;
|
||||
if (levelAccumulator > 0)
|
||||
iterationCallback.handleEdgeTablePixel (x, jmin (0xff, levelAccumulator));
|
||||
{
|
||||
if (levelAccumulator >> 8)
|
||||
levelAccumulator = 0xff;
|
||||
|
||||
iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
|
||||
}
|
||||
}
|
||||
|
||||
if (++x >= clipRight)
|
||||
|
|
@ -17229,8 +17230,7 @@ public:
|
|||
const int numPix = endOfRun - x;
|
||||
|
||||
if (numPix > 0)
|
||||
iterationCallback.handleEdgeTableLine (x, numPix,
|
||||
jmin (correctedLevel, 0xff));
|
||||
iterationCallback.handleEdgeTableLine (x, numPix, correctedLevel);
|
||||
}
|
||||
|
||||
// save the bit at the end to be drawn next time round the loop.
|
||||
|
|
@ -17261,10 +17261,10 @@ private:
|
|||
// table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
|
||||
int* table;
|
||||
int top, height, maxEdgesPerLine, lineStrideElements;
|
||||
bool nonZeroWinding;
|
||||
|
||||
void addEdgePoint (const int x, const int y, const int winding) throw();
|
||||
void remapTableForNumEdges (const int newNumEdgesPerLine) throw();
|
||||
void clearLineSection (const int y, int minX, int maxX) throw();
|
||||
};
|
||||
|
||||
#endif // __JUCE_EDGETABLE_JUCEHEADER__
|
||||
|
|
@ -40217,7 +40217,7 @@ public:
|
|||
*/
|
||||
PathFlatteningIterator (const Path& path,
|
||||
const AffineTransform& transform = AffineTransform::identity,
|
||||
float tolerence = 9.0f) throw();
|
||||
float tolerence = 6.0f) throw();
|
||||
|
||||
/** Destructor. */
|
||||
~PathFlatteningIterator() throw();
|
||||
|
|
|
|||
|
|
@ -33,13 +33,121 @@ BEGIN_JUCE_NAMESPACE
|
|||
const int juce_edgeTableDefaultEdgesPerLine = 32;
|
||||
|
||||
//==============================================================================
|
||||
EdgeTable::EdgeTable (const int top_, const int height_) throw()
|
||||
EdgeTable::EdgeTable (const int top_, const int height_,
|
||||
const Path& path, const AffineTransform& transform) throw()
|
||||
: top (top_),
|
||||
height (height_),
|
||||
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
|
||||
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
|
||||
{
|
||||
table = (int*) juce_calloc (height * lineStrideElements * sizeof (int));
|
||||
table = (int*) juce_malloc (height_ * lineStrideElements * sizeof (int));
|
||||
int* t = table;
|
||||
for (int i = height_; --i >= 0;)
|
||||
{
|
||||
*t = 0;
|
||||
t += lineStrideElements;
|
||||
}
|
||||
|
||||
const int topLimit = top << 8;
|
||||
const int bottomLimit = height << 8;
|
||||
PathFlatteningIterator iter (path, transform);
|
||||
|
||||
while (iter.next())
|
||||
{
|
||||
int y1 = roundFloatToInt (iter.y1 * 256.0f);
|
||||
int y2 = roundFloatToInt (iter.y2 * 256.0f);
|
||||
|
||||
if (y1 != y2)
|
||||
{
|
||||
y1 -= topLimit;
|
||||
y2 -= topLimit;
|
||||
|
||||
const double startX = 256.0f * iter.x1;
|
||||
const int startY = y1;
|
||||
const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
|
||||
int winding = -1;
|
||||
|
||||
if (y1 > y2)
|
||||
{
|
||||
swapVariables (y1, y2);
|
||||
winding = 1;
|
||||
}
|
||||
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
|
||||
if (y2 > bottomLimit)
|
||||
y2 = bottomLimit;
|
||||
|
||||
const int stepSize = jlimit (1, 256, 256 / (1 + (int) fabs (multiplier)));
|
||||
|
||||
while (y1 < y2)
|
||||
{
|
||||
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
|
||||
|
||||
addEdgePoint (roundDoubleToInt (startX + multiplier * (y1 - startY)),
|
||||
y1 >> 8, winding * step);
|
||||
|
||||
y1 += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! path.isUsingNonZeroWinding())
|
||||
{
|
||||
int* lineStart = table;
|
||||
|
||||
for (int i = height; --i >= 0;)
|
||||
{
|
||||
int* line = lineStart;
|
||||
lineStart += lineStrideElements;
|
||||
int num = *line;
|
||||
int level = 0;
|
||||
int lastCorrected = 0;
|
||||
|
||||
while (--num >= 0)
|
||||
{
|
||||
line += 2;
|
||||
level += *line;
|
||||
int corrected = abs (level);
|
||||
if (corrected >> 8)
|
||||
{
|
||||
corrected &= 511;
|
||||
if (corrected >> 8)
|
||||
corrected = 511 - corrected;
|
||||
}
|
||||
|
||||
*line = corrected - lastCorrected;
|
||||
lastCorrected = corrected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw()
|
||||
: top (rectangleToAdd.getY()),
|
||||
height (jmax (1, rectangleToAdd.getHeight())),
|
||||
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
|
||||
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
|
||||
{
|
||||
jassert (! rectangleToAdd.isEmpty());
|
||||
|
||||
table = (int*) juce_malloc (height * lineStrideElements * sizeof (int));
|
||||
*table = 0;
|
||||
|
||||
const int x1 = rectangleToAdd.getX();
|
||||
const int x2 = rectangleToAdd.getRight();
|
||||
|
||||
int* t = table;
|
||||
for (int i = rectangleToAdd.getHeight(); --i >= 0;)
|
||||
{
|
||||
t[0] = 2;
|
||||
t[1] = x1;
|
||||
t[2] = 256;
|
||||
t[3] = x2;
|
||||
t[4] = -256;
|
||||
t += lineStrideElements;
|
||||
}
|
||||
}
|
||||
|
||||
EdgeTable::EdgeTable (const EdgeTable& other) throw()
|
||||
|
|
@ -109,7 +217,6 @@ void EdgeTable::optimiseTable() throw()
|
|||
remapTableForNumEdges (maxLineElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw()
|
||||
{
|
||||
jassert (y >= 0 && y < height)
|
||||
|
|
@ -146,93 +253,47 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw
|
|||
lineStart[0]++;
|
||||
}
|
||||
|
||||
void EdgeTable::clearLineSection (const int y, int minX, int maxX) throw()
|
||||
{
|
||||
// int* line = table + lineStrideElements * y;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void EdgeTable::addPath (const Path& path, const AffineTransform& transform) throw()
|
||||
void EdgeTable::clipToRectangle (const Rectangle& r) throw()
|
||||
{
|
||||
const int bottomLimit = height << 8;
|
||||
const int rectTop = jmax (0, r.getY() - top);
|
||||
const int rectBottom = jmin (height, r.getBottom() - top);
|
||||
|
||||
PathFlatteningIterator iter (path, transform);
|
||||
for (int i = rectTop - 1; --i >= 0;)
|
||||
table [lineStrideElements * i] = 0;
|
||||
|
||||
while (iter.next())
|
||||
for (int i = rectBottom; i < height; ++i)
|
||||
table [lineStrideElements * i] = 0;
|
||||
|
||||
for (int i = rectTop; i < rectBottom; ++i)
|
||||
{
|
||||
int y1 = roundFloatToInt (iter.y1 * 256.0f) - (top << 8);
|
||||
int y2 = roundFloatToInt (iter.y2 * 256.0f) - (top << 8);
|
||||
|
||||
if (y1 != y2)
|
||||
{
|
||||
const int oldY1 = y1;
|
||||
const double x1 = 256.0 * iter.x1;
|
||||
const double x2 = 256.0 * iter.x2;
|
||||
const double multiplier = (x2 - x1) / (y2 - y1);
|
||||
int winding = -1;
|
||||
|
||||
if (y1 > y2)
|
||||
{
|
||||
swapVariables (y1, y2);
|
||||
winding = 1;
|
||||
}
|
||||
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
|
||||
if (y2 > bottomLimit)
|
||||
y2 = bottomLimit;
|
||||
|
||||
const int stepSize = jlimit (1, 256, 256 / (1 + abs ((int) multiplier)));
|
||||
|
||||
while (y1 < y2)
|
||||
{
|
||||
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
|
||||
|
||||
addEdgePoint (roundDoubleToInt (x1 + multiplier * (y1 - oldY1)),
|
||||
y1 >> 8, winding * step);
|
||||
|
||||
y1 += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! path.isUsingNonZeroWinding())
|
||||
{
|
||||
int* lineStart = table;
|
||||
|
||||
for (int i = height; --i >= 0;)
|
||||
{
|
||||
int* line = lineStart;
|
||||
lineStart += lineStrideElements;
|
||||
int num = *line;
|
||||
int level = 0;
|
||||
int lastCorrected = 0;
|
||||
|
||||
while (--num >= 0)
|
||||
{
|
||||
line += 2;
|
||||
level += *line;
|
||||
int corrected = abs (level);
|
||||
if (corrected >> 8)
|
||||
{
|
||||
corrected &= 511;
|
||||
if (corrected >> 8)
|
||||
corrected = 511 - corrected;
|
||||
}
|
||||
|
||||
*line = corrected - lastCorrected;
|
||||
lastCorrected = corrected;
|
||||
}
|
||||
}
|
||||
clearLineSection (i, -INT_MAX, r.getX());
|
||||
clearLineSection (i, r.getRight(), INT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
/*void EdgeTable::clipToRectangle (const Rectangle& r) throw()
|
||||
void EdgeTable::excludeRectangle (const Rectangle& r) throw()
|
||||
{
|
||||
const int rectTop = jmax (0, r.getY() - top);
|
||||
const int rectBottom = jmin (height, r.getBottom() - top);
|
||||
|
||||
for (int i = rectTop; i < rectBottom; ++i)
|
||||
clearLineSection (i, r.getX(), r.getRight());
|
||||
}
|
||||
|
||||
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
|
||||
{
|
||||
}
|
||||
|
||||
void EdgeTable::intersectWith (const EdgeTable& other)
|
||||
void EdgeTable::clipToImageAlpha (Image& image, int x, int y) throw()
|
||||
{
|
||||
}
|
||||
|
||||
void EdgeTable::generateFromImageAlpha (Image& image, int x, int y) throw()
|
||||
{
|
||||
}*/
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -42,15 +42,22 @@ class JUCE_API EdgeTable
|
|||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty edge table ready to have paths added.
|
||||
/** Creates an edge table containing a path.
|
||||
|
||||
A table is created with a fixed vertical size, and only sections of paths
|
||||
which lie within their range will be added to the table.
|
||||
A table is created with a fixed vertical range, and only sections of the path
|
||||
which lie within this range will be added to the table.
|
||||
|
||||
@param y the lowest y co-ordinate that the table can contain
|
||||
@param y the top y co-ordinate that the table can contain
|
||||
@param height the number of horizontal lines it contains
|
||||
@param pathToAdd the path to add to the table
|
||||
@param transform a transform to apply to the path being added
|
||||
*/
|
||||
EdgeTable (const int y, const int height) throw();
|
||||
EdgeTable (const int y, const int height,
|
||||
const Path& pathToAdd, const AffineTransform& transform) throw();
|
||||
|
||||
/** Creates an edge table containing a rectangle.
|
||||
*/
|
||||
EdgeTable (const Rectangle& rectangleToAdd) throw();
|
||||
|
||||
/** Creates a copy of another edge table. */
|
||||
EdgeTable (const EdgeTable& other) throw();
|
||||
|
|
@ -62,21 +69,10 @@ public:
|
|||
~EdgeTable() throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Adds edges to the table for a path.
|
||||
|
||||
This will add horizontal lines to the edge table for any parts of the path
|
||||
which lie within the vertical bounds for which this table was created.
|
||||
|
||||
@param path the path to add
|
||||
@param transform an optional transform to apply to the path while it's
|
||||
being added
|
||||
*/
|
||||
void addPath (const Path& path,
|
||||
const AffineTransform& transform) throw();
|
||||
|
||||
/*void clipToRectangle (const Rectangle& r) throw();
|
||||
void intersectWith (const EdgeTable& other);
|
||||
void generateFromImageAlpha (Image& image, int x, int y) throw();*/
|
||||
void clipToRectangle (const Rectangle& r) throw();
|
||||
void excludeRectangle (const Rectangle& r) throw();
|
||||
void clipToEdgeTable (const EdgeTable& other);
|
||||
void clipToImageAlpha (Image& image, int x, int y) throw();
|
||||
|
||||
/** Reduces the amount of space the table has allocated.
|
||||
|
||||
|
|
@ -166,7 +162,12 @@ public:
|
|||
{
|
||||
levelAccumulator >>= 8;
|
||||
if (levelAccumulator > 0)
|
||||
iterationCallback.handleEdgeTablePixel (x, jmin (0xff, levelAccumulator));
|
||||
{
|
||||
if (levelAccumulator >> 8)
|
||||
levelAccumulator = 0xff;
|
||||
|
||||
iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
|
||||
}
|
||||
}
|
||||
|
||||
if (++x >= clipRight)
|
||||
|
|
@ -187,8 +188,7 @@ public:
|
|||
const int numPix = endOfRun - x;
|
||||
|
||||
if (numPix > 0)
|
||||
iterationCallback.handleEdgeTableLine (x, numPix,
|
||||
jmin (correctedLevel, 0xff));
|
||||
iterationCallback.handleEdgeTableLine (x, numPix, correctedLevel);
|
||||
}
|
||||
|
||||
// save the bit at the end to be drawn next time round the loop.
|
||||
|
|
@ -220,10 +220,10 @@ private:
|
|||
// table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
|
||||
int* table;
|
||||
int top, height, maxEdgesPerLine, lineStrideElements;
|
||||
bool nonZeroWinding;
|
||||
|
||||
void addEdgePoint (const int x, const int y, const int winding) throw();
|
||||
void remapTableForNumEdges (const int newNumEdgesPerLine) throw();
|
||||
void clearLineSection (const int y, int minX, int maxX) throw();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1362,8 +1362,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPath (int clipX, int clipY, in
|
|||
|
||||
if (getPathBounds (clipX, clipY, clipW, clipH, path, transform, cx, cy, cw, ch))
|
||||
{
|
||||
EdgeTable edgeTable (0, ch);
|
||||
edgeTable.addPath (path, transform.translated ((float) -cx, (float) -cy));
|
||||
EdgeTable edgeTable (0, ch, path, transform.translated ((float) -cx, (float) -cy));
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (cx, cy, cw, ch, stride, pixelStride);
|
||||
|
|
@ -1490,8 +1489,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPathWithImage (int x, int y, i
|
|||
{
|
||||
if (Rectangle::intersectRectangles (x, y, w, h, imageX, imageY, sourceImage.getWidth(), sourceImage.getHeight()))
|
||||
{
|
||||
EdgeTable edgeTable (0, h);
|
||||
edgeTable.addPath (path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
|
||||
EdgeTable edgeTable (0, h, path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (x, y, w, h, stride, pixelStride);
|
||||
|
|
|
|||
|
|
@ -309,17 +309,21 @@ void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <fl
|
|||
|
||||
const float scale = font->height * font->horizontalScale;
|
||||
const int num = xOffsets.size();
|
||||
float* const x = &(xOffsets.getReference(0));
|
||||
|
||||
if (font->kerning != 0)
|
||||
if (num > 0)
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] = (x[i] + i * font->kerning) * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] *= scale;
|
||||
float* const x = &(xOffsets.getReference(0));
|
||||
|
||||
if (font->kerning != 0)
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] = (x[i] + i * font->kerning) * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < num; ++i)
|
||||
x[i] *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -455,7 +459,7 @@ public:
|
|||
|
||||
g.fillAlphaChannel (*bitmap [bitmapToUse],
|
||||
xOrigin [bitmapToUse] + (int) xFloor,
|
||||
yOrigin [bitmapToUse] + (int) floorf (y));
|
||||
yOrigin [bitmapToUse] + roundFloatToInt(y));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1603,8 +1603,8 @@ Image* Path::createMaskBitmap (const AffineTransform& transform,
|
|||
|
||||
Image* im = new Image (Image::SingleChannel, imagePosition.getWidth(), imagePosition.getHeight(), true);
|
||||
|
||||
EdgeTable edgeTable (0, imagePosition.getHeight());
|
||||
edgeTable.addPath (*this, transform.translated (-imagePosition.getX(), -imagePosition.getY()));
|
||||
EdgeTable edgeTable (0, imagePosition.getHeight(), *this,
|
||||
transform.translated (-imagePosition.getX(), -imagePosition.getY()));
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* const pixels = (uint8*) im->lockPixelDataReadWrite (0, 0, imagePosition.getWidth(), imagePosition.getHeight(), stride, pixelStride);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
*/
|
||||
PathFlatteningIterator (const Path& path,
|
||||
const AffineTransform& transform = AffineTransform::identity,
|
||||
float tolerence = 9.0f) throw();
|
||||
float tolerence = 6.0f) throw();
|
||||
|
||||
/** Destructor. */
|
||||
~PathFlatteningIterator() throw();
|
||||
|
|
|
|||
|
|
@ -239,20 +239,47 @@ static void addEdgeAndJoint (Path& destPath,
|
|||
else
|
||||
{
|
||||
// curved joints
|
||||
float angle = atan2f (x2 - midX, y2 - midY);
|
||||
float angle1 = atan2f (x2 - midX, y2 - midY);
|
||||
float angle2 = atan2f (x3 - midX, y3 - midY);
|
||||
|
||||
while (angle < angle2 - 0.01f)
|
||||
angle2 -= float_Pi * 2.0f;
|
||||
const float angleIncrement = 0.1f;
|
||||
|
||||
destPath.lineTo (x2, y2);
|
||||
|
||||
while (angle > angle2)
|
||||
if (fabs (angle1 - angle2) > angleIncrement)
|
||||
{
|
||||
destPath.lineTo (midX + width * sinf (angle),
|
||||
midY + width * cosf (angle));
|
||||
if (angle2 > angle1 + float_Pi
|
||||
|| (angle2 < angle1 && angle2 >= angle1 - float_Pi))
|
||||
{
|
||||
if (angle2 > angle1)
|
||||
angle2 -= float_Pi * 2.0f;
|
||||
|
||||
angle -= 0.1f;
|
||||
jassert (angle1 <= angle2 + float_Pi);
|
||||
|
||||
angle1 -= angleIncrement;
|
||||
while (angle1 > angle2)
|
||||
{
|
||||
destPath.lineTo (midX + width * sinf (angle1),
|
||||
midY + width * cosf (angle1));
|
||||
|
||||
angle1 -= angleIncrement;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (angle1 > angle2)
|
||||
angle1 -= float_Pi * 2.0f;
|
||||
|
||||
jassert (angle1 >= angle2 - float_Pi);
|
||||
|
||||
angle1 += angleIncrement;
|
||||
while (angle1 < angle2)
|
||||
{
|
||||
destPath.lineTo (midX + width * sinf (angle1),
|
||||
midY + width * cosf (angle1));
|
||||
|
||||
angle1 += angleIncrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destPath.lineTo (x3, y3);
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ public:
|
|||
if (state->fontRef != 0)
|
||||
{
|
||||
CGGlyph g = glyphNumber;
|
||||
CGContextShowGlyphsAtPoint (context, x, flipHeight - y, &g, 1);
|
||||
CGContextShowGlyphsAtPoint (context, x, flipHeight - roundFloatToInt (y), &g, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,16 @@
|
|||
// compiled on its own).
|
||||
#if JUCE_INCLUDED_FILE
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define SUPPORT_10_4_FONTS 1
|
||||
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
@interface NSFont (PrivateHack)
|
||||
- (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
|
||||
@end
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class MacTypeface : public Typeface
|
||||
|
|
@ -80,6 +90,9 @@ public:
|
|||
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
#else
|
||||
nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
|
||||
|
||||
|
|
@ -111,18 +124,40 @@ public:
|
|||
renderingTransform.c = 0.15f;
|
||||
}
|
||||
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
|
||||
#endif
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
if (atsFont == 0)
|
||||
atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
|
||||
|
||||
fontRef = CGFontCreateWithPlatformFont ((void*) &atsFont);
|
||||
|
||||
const float totalHeight = fabsf ([nsFont ascender]) + fabsf([nsFont descender]);
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = 1024.0f / totalHeight;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
|
||||
|
||||
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
|
||||
unitsToHeightScaleFactor = 1.0f / totalHeight;
|
||||
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
~MacTypeface()
|
||||
{
|
||||
[nsFont release];
|
||||
CGFontRelease (fontRef);
|
||||
|
||||
if (fontRef != 0)
|
||||
CGFontRelease (fontRef);
|
||||
|
||||
delete charToGlyphMapper;
|
||||
}
|
||||
|
||||
|
|
@ -138,50 +173,88 @@ public:
|
|||
|
||||
float getStringWidth (const String& text)
|
||||
{
|
||||
if (fontRef == 0)
|
||||
if (fontRef == 0 || text.isEmpty())
|
||||
return 0;
|
||||
|
||||
Array <int> glyphs (128);
|
||||
createGlyphsForString (text, glyphs);
|
||||
|
||||
if (glyphs.size() == 0)
|
||||
return 0;
|
||||
const int length = text.length();
|
||||
CGGlyph* const glyphs = createGlyphsForString (text, length);
|
||||
|
||||
int x = 0;
|
||||
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
|
||||
for (int i = 0; i < glyphs.size(); ++i)
|
||||
x += advances [i * 2];
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
|
||||
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
x += advances[i].width;
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int* const advances = (int*) juce_malloc (length * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
|
||||
for (int i = 0; i < length; ++i)
|
||||
x += advances[i];
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
|
||||
juce_free (glyphs);
|
||||
|
||||
juce_free (advances);
|
||||
return x * unitsToHeightScaleFactor;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets)
|
||||
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
|
||||
{
|
||||
if (fontRef == 0)
|
||||
return;
|
||||
|
||||
createGlyphsForString (text, glyphs);
|
||||
|
||||
xOffsets.add (0);
|
||||
if (glyphs.size() == 0)
|
||||
|
||||
if (fontRef == 0 || text.isEmpty())
|
||||
return;
|
||||
|
||||
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
|
||||
const int length = text.length();
|
||||
CGGlyph* const glyphs = createGlyphsForString (text, length);
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
|
||||
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
|
||||
|
||||
int x = 0;
|
||||
for (int i = 0; i < glyphs.size(); ++i)
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
x += advances [i * 2];
|
||||
x += advances[i].width;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int* const advances = (int*) juce_malloc (length * sizeof (int));
|
||||
|
||||
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
|
||||
{
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
x += advances [i];
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (glyphs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
}
|
||||
|
||||
juce_free (advances);
|
||||
juce_free (glyphs);
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
|
|
@ -247,15 +320,28 @@ private:
|
|||
AffineTransform pathTransform;
|
||||
#endif
|
||||
|
||||
void createGlyphsForString (const String& text, Array <int>& dest) throw()
|
||||
CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw()
|
||||
{
|
||||
#if SUPPORT_10_4_FONTS
|
||||
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
|
||||
{
|
||||
NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length);
|
||||
|
||||
for (int i = 0; i < length; ++i)
|
||||
g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]];
|
||||
|
||||
return (CGGlyph*) g;
|
||||
}
|
||||
#endif
|
||||
if (charToGlyphMapper == 0)
|
||||
charToGlyphMapper = new CharToGlyphMapper (fontRef);
|
||||
|
||||
const juce_wchar* t = (const juce_wchar*) text;
|
||||
CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length);
|
||||
|
||||
while (*t != 0)
|
||||
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
|
||||
for (int i = 0; i < length; ++i)
|
||||
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
// Reads a CGFontRef's character map table to convert unicode into glyph numbers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue