upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)

This commit is contained in:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -43,14 +43,10 @@ namespace RenderingHelpers
class TranslationOrTransform
{
public:
TranslationOrTransform() noexcept {}
TranslationOrTransform() = default;
TranslationOrTransform (Point<int> origin) noexcept : offset (origin) {}
TranslationOrTransform (const TranslationOrTransform& other) noexcept
: complexTransform (other.complexTransform), offset (other.offset),
isOnlyTranslated (other.isOnlyTranslated), isRotated (other.isRotated)
{
}
TranslationOrTransform (const TranslationOrTransform& other) = default;
AffineTransform getTransform() const noexcept
{
@ -156,7 +152,7 @@ public:
reset();
}
~GlyphCache()
~GlyphCache() override
{
getSingletonPointer() = nullptr;
}
@ -194,35 +190,34 @@ public:
{
const ScopedLock sl (lock);
if (auto* g = findExistingGlyph (font, glyphNumber))
if (auto g = findExistingGlyph (font, glyphNumber))
{
++hits;
return g;
}
++misses;
auto* g = getGlyphForReuse();
auto g = getGlyphForReuse();
jassert (g != nullptr);
g->generate (font, glyphNumber);
return g;
}
private:
friend struct ContainerDeletePolicy<CachedGlyphType>;
ReferenceCountedArray<CachedGlyphType> glyphs;
Atomic<int> accessCounter, hits, misses;
CriticalSection lock;
CachedGlyphType* findExistingGlyph (const Font& font, int glyphNumber) const noexcept
ReferenceCountedObjectPtr<CachedGlyphType> findExistingGlyph (const Font& font, int glyphNumber) const noexcept
{
for (auto* g : glyphs)
for (auto g : glyphs)
if (g->glyph == glyphNumber && g->font == font)
return g;
return *g;
return nullptr;
return {};
}
CachedGlyphType* getGlyphForReuse()
ReferenceCountedObjectPtr<CachedGlyphType> getGlyphForReuse()
{
if (hits.get() + misses.get() > glyphs.size() * 16)
{
@ -233,8 +228,8 @@ private:
misses = 0;
}
if (auto* g = findLeastRecentlyUsedGlyph())
return g;
if (auto g = findLeastRecentlyUsedGlyph())
return *g;
addNewGlyphSlots (32);
return glyphs.getLast();
@ -284,7 +279,7 @@ template <class RendererType>
class CachedGlyphEdgeTable : public ReferenceCountedObject
{
public:
CachedGlyphEdgeTable() {}
CachedGlyphEdgeTable() = default;
void draw (RendererType& state, Point<float> pos) const
{
@ -581,7 +576,7 @@ namespace EdgeTableFillers
SolidColour (const Image::BitmapData& image, PixelARGB colour)
: destData (image), sourceColour (colour)
{
if (sizeof (PixelType) == 3 && destData.pixelStride == sizeof (PixelType))
if (sizeof (PixelType) == 3 && (size_t) destData.pixelStride == sizeof (PixelType))
{
areRGBComponentsEqual = sourceColour.getRed() == sourceColour.getGreen()
&& sourceColour.getGreen() == sourceColour.getBlue();
@ -690,11 +685,11 @@ namespace EdgeTableFillers
forcedinline void replaceLine (PixelRGB* dest, PixelARGB colour, int width) const noexcept
{
if (destData.pixelStride == sizeof (*dest))
if ((size_t) destData.pixelStride == sizeof (*dest))
{
if (areRGBComponentsEqual) // if all the component values are the same, we can cheat..
{
memset (dest, colour.getRed(), (size_t) width * 3);
memset ((void*) dest, colour.getRed(), (size_t) width * 3);
}
else
{
@ -735,8 +730,8 @@ namespace EdgeTableFillers
forcedinline void replaceLine (PixelAlpha* dest, const PixelARGB colour, int width) const noexcept
{
if (destData.pixelStride == sizeof (*dest))
memset (dest, colour.getAlpha(), (size_t) width);
if ((size_t) destData.pixelStride == sizeof (*dest))
memset ((void*) dest, colour.getAlpha(), (size_t) width);
else
JUCE_PERFORM_PIXEL_OP_LOOP (setAlpha (colour.getAlpha()))
}
@ -966,7 +961,7 @@ namespace EdgeTableFillers
&& srcData.pixelFormat == Image::RGB
&& destData.pixelFormat == Image::RGB)
{
memcpy (dest, src, (size_t) (width * srcStride));
memcpy ((void*) dest, src, (size_t) (width * srcStride));
}
else
{
@ -1398,7 +1393,7 @@ namespace EdgeTableFillers
private:
struct BresenhamInterpolator
{
BresenhamInterpolator() noexcept {}
BresenhamInterpolator() = default;
void set (int n1, int n2, int steps, int offsetInt) noexcept
{
@ -1629,8 +1624,8 @@ struct ClipRegions
{
struct Base : public SingleThreadedReferenceCountedObject
{
Base() {}
virtual ~Base() {}
Base() = default;
~Base() override = default;
using Ptr = ReferenceCountedObjectPtr<Base>;
@ -1671,13 +1666,13 @@ struct ClipRegions
using Ptr = typename Base::Ptr;
Ptr clone() const override { return new EdgeTableRegion (*this); }
Ptr clone() const override { return *new EdgeTableRegion (*this); }
Ptr applyClipTo (const Ptr& target) const override { return target->clipToEdgeTable (edgeTable); }
Ptr clipToRectangle (Rectangle<int> r) override
{
edgeTable.clipToRectangle (r);
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr clipToRectangleList (const RectangleList<int>& r) override
@ -1688,26 +1683,26 @@ struct ClipRegions
for (auto& i : inverse)
edgeTable.excludeRectangle (i);
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr excludeClipRectangle (Rectangle<int> r) override
{
edgeTable.excludeRectangle (r);
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr clipToPath (const Path& p, const AffineTransform& transform) override
{
EdgeTable et (edgeTable.getMaximumBounds(), p, transform);
edgeTable.clipToEdgeTable (et);
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr clipToEdgeTable (const EdgeTable& et) override
{
edgeTable.clipToEdgeTable (et);
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, Graphics::ResamplingQuality quality) override
@ -1726,11 +1721,11 @@ struct ClipRegions
auto imageY = ((ty + 128) >> 8);
if (image.getFormat() == Image::ARGB)
straightClipImage (srcData, imageX, imageY, (PixelARGB*) 0);
straightClipImage (srcData, imageX, imageY, (PixelARGB*) nullptr);
else
straightClipImage (srcData, imageX, imageY, (PixelAlpha*) 0);
straightClipImage (srcData, imageX, imageY, (PixelAlpha*) nullptr);
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
}
@ -1747,12 +1742,12 @@ struct ClipRegions
if (! edgeTable.isEmpty())
{
if (image.getFormat() == Image::ARGB)
transformedClipImage (srcData, transform, quality, (PixelARGB*) 0);
transformedClipImage (srcData, transform, quality, (PixelARGB*) nullptr);
else
transformedClipImage (srcData, transform, quality, (PixelAlpha*) 0);
transformedClipImage (srcData, transform, quality, (PixelAlpha*) nullptr);
}
return edgeTable.isEmpty() ? nullptr : this;
return edgeTable.isEmpty() ? Ptr() : Ptr (*this);
}
void translate (Point<int> delta) override
@ -1852,25 +1847,25 @@ struct ClipRegions
using Ptr = typename Base::Ptr;
Ptr clone() const override { return new RectangleListRegion (*this); }
Ptr clone() const override { return *new RectangleListRegion (*this); }
Ptr applyClipTo (const Ptr& target) const override { return target->clipToRectangleList (clip); }
Ptr clipToRectangle (Rectangle<int> r) override
{
clip.clipTo (r);
return clip.isEmpty() ? nullptr : this;
return clip.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr clipToRectangleList (const RectangleList<int>& r) override
{
clip.clipTo (r);
return clip.isEmpty() ? nullptr : this;
return clip.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr excludeClipRectangle (Rectangle<int> r) override
{
clip.subtract (r);
return clip.isEmpty() ? nullptr : this;
return clip.isEmpty() ? Ptr() : Ptr (*this);
}
Ptr clipToPath (const Path& p, const AffineTransform& transform) override { return toEdgeTable()->clipToPath (p, transform); }
@ -2069,9 +2064,9 @@ struct ClipRegions
JUCE_DECLARE_NON_COPYABLE (SubRectangleIteratorFloat)
};
Ptr toEdgeTable() const { return new EdgeTableRegion (clip); }
Ptr toEdgeTable() const { return *new EdgeTableRegion (clip); }
RectangleListRegion& operator= (const RectangleListRegion&);
RectangleListRegion& operator= (const RectangleListRegion&) = delete;
};
};
@ -2268,7 +2263,7 @@ public:
auto clipped = clip->getClipBounds().getIntersection (r);
if (! clipped.isEmpty())
fillShape (new RectangleListRegionType (clipped), false);
fillShape (*new RectangleListRegionType (clipped), false);
}
}
@ -2283,7 +2278,7 @@ public:
auto clipped = clip->getClipBounds().toFloat().getIntersection (r);
if (! clipped.isEmpty())
fillShape (new EdgeTableRegionType (clipped), false);
fillShape (*new EdgeTableRegionType (clipped), false);
}
}
@ -2337,7 +2332,7 @@ public:
if (transform.isIdentity())
{
fillShape (new EdgeTableRegionType (list), false);
fillShape (*new EdgeTableRegionType (list), false);
}
else if (! transform.isRotated)
{
@ -2348,7 +2343,7 @@ public:
else
transformed.transformAll (transform.getTransform());
fillShape (new EdgeTableRegionType (transformed), false);
fillShape (*new EdgeTableRegionType (transformed), false);
}
else
{
@ -2365,7 +2360,7 @@ public:
auto clipRect = clip->getClipBounds();
if (path.getBoundsTransformed (trans).getSmallestIntegerContainer().intersects (clipRect))
fillShape (new EdgeTableRegionType (clipRect, path, trans), false);
fillShape (*new EdgeTableRegionType (clipRect, path, trans), false);
}
}
@ -2384,7 +2379,7 @@ public:
edgeTableClip->edgeTable.multiplyLevels (1.0f + 1.6f * brightness);
}
fillShape (edgeTableClip, false);
fillShape (*edgeTableClip, false);
}
}
@ -2398,15 +2393,15 @@ public:
void drawImage (const Image& sourceImage, const AffineTransform& trans)
{
if (clip != nullptr && ! fillType.colour.isTransparent())
renderImage (sourceImage, trans, nullptr);
renderImage (sourceImage, trans, {});
}
static bool isOnlyTranslationAllowingError (const AffineTransform& t, float tolerence) noexcept
static bool isOnlyTranslationAllowingError (const AffineTransform& t, float tolerance) noexcept
{
return std::abs (t.mat01) < tolerence
&& std::abs (t.mat10) < tolerence
&& std::abs (t.mat00 - 1.0f) < tolerence
&& std::abs (t.mat11 - 1.0f) < tolerence;
return std::abs (t.mat01) < tolerance
&& std::abs (t.mat10) < tolerance
&& std::abs (t.mat00 - 1.0f) < tolerance
&& std::abs (t.mat11 - 1.0f) < tolerance;
}
void renderImage (const Image& sourceImage, const AffineTransform& trans, const BaseRegionType* tiledFillClipRegion)
@ -2435,7 +2430,7 @@ public:
area = area.getIntersection (getThis().getMaximumBounds());
if (! area.isEmpty())
if (auto c = clip->applyClipTo (new EdgeTableRegionType (area)))
if (auto c = clip->applyClipTo (*new EdgeTableRegionType (area)))
c->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty, false);
}
@ -2491,7 +2486,7 @@ public:
}
else if (fillType.isTiledImage())
{
renderImage (fillType.image, fillType.transform, shapeToFill);
renderImage (fillType.image, fillType.transform, shapeToFill.get());
}
else
{
@ -2529,10 +2524,7 @@ public:
{
}
SoftwareRendererSavedState (const SoftwareRendererSavedState& other)
: BaseClass (other), image (other.image), font (other.font)
{
}
SoftwareRendererSavedState (const SoftwareRendererSavedState& other) = default;
SoftwareRendererSavedState* beginTransparencyLayer (float opacity)
{
@ -2610,7 +2602,7 @@ public:
std::unique_ptr<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t, fontHeight));
if (et != nullptr)
fillShape (new EdgeTableRegionType (*et), false);
fillShape (*new EdgeTableRegionType (*et), false);
}
}
}
@ -2641,9 +2633,9 @@ public:
switch (destData.pixelFormat)
{
case Image::ARGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelARGB*) 0); break;
case Image::RGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelRGB*) 0); break;
default: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelAlpha*) 0); break;
case Image::ARGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelARGB*) nullptr); break;
case Image::RGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelRGB*) nullptr); break;
default: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelAlpha*) nullptr); break;
}
}
@ -2658,9 +2650,9 @@ public:
switch (destData.pixelFormat)
{
case Image::ARGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelARGB*) 0); break;
case Image::RGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelRGB*) 0); break;
default: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelAlpha*) 0); break;
case Image::ARGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelARGB*) nullptr); break;
case Image::RGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelRGB*) nullptr); break;
default: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelAlpha*) nullptr); break;
}
}
@ -2669,7 +2661,7 @@ public:
Font font;
private:
SoftwareRendererSavedState& operator= (const SoftwareRendererSavedState&);
SoftwareRendererSavedState& operator= (const SoftwareRendererSavedState&) = delete;
};
//==============================================================================
@ -2681,7 +2673,7 @@ public:
: currentState (initialState)
{}
SavedStateStack() noexcept {}
SavedStateStack() = default;
void initialise (StateObjectType* state)
{
@ -2765,7 +2757,7 @@ public:
protected:
StackBasedLowLevelGraphicsContext (SavedStateType* initialState) : stack (initialState) {}
StackBasedLowLevelGraphicsContext() {}
StackBasedLowLevelGraphicsContext() = default;
RenderingHelpers::SavedStateStack<SavedStateType> stack;
};

View File

@ -94,11 +94,37 @@ bool TextLayout::createNativeLayout (const AttributedString&)
#else
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \
STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
STATICMETHOD (createFromAsset, "createFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)Landroid/graphics/Typeface;")
DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface");
DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (constructor, "<init>", "()V") \
METHOD (computeBounds, "computeBounds", "(Landroid/graphics/RectF;Z)V")
DECLARE_JNI_CLASS (AndroidPath, "android/graphics/Path")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
METHOD (constructor, "<init>", "()V") \
FIELD (left, "left", "F") \
FIELD (right, "right", "F") \
FIELD (top, "top", "F") \
FIELD (bottom, "bottom", "F") \
METHOD (roundOut, "roundOut", "(Landroid/graphics/Rect;)V")
DECLARE_JNI_CLASS (AndroidRectF, "android/graphics/RectF")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
STATICMETHOD (getInstance, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;") \
METHOD (update, "update", "([B)V") \
METHOD (digest, "digest", "()[B")
DECLARE_JNI_CLASS (JavaMessageDigest, "java/security/MessageDigest")
#undef JNI_CLASS_MEMBERS
//==============================================================================
@ -136,8 +162,7 @@ public:
JNIEnv* const env = getEnv();
// First check whether there's an embedded asset with this font name:
typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromAsset,
javaString ("fonts/" + name).get()));
typeface = GlobalRef (getTypefaceFromAsset (name));
if (typeface.get() == nullptr)
{
@ -150,12 +175,12 @@ public:
fontFile = findFontFile (name, isBold, isItalic);
if (fontFile.exists())
typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
javaString (fontFile.getFullPathName()).get()));
typeface = GlobalRef (LocalRef<jobject>(env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
javaString (fontFile.getFullPathName()).get())));
else
typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create,
javaString (getName()).get(),
(isBold ? 1 : 0) + (isItalic ? 2 : 0)));
typeface = GlobalRef (LocalRef<jobject>(env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create,
javaString (getName()).get(),
(isBold ? 1 : 0) + (isItalic ? 2 : 0))));
}
initialise (env);
@ -164,23 +189,24 @@ public:
AndroidTypeface (const void* data, size_t size)
: Typeface (String (static_cast<uint64> (reinterpret_cast<uintptr_t> (data))), String())
{
JNIEnv* const env = getEnv();
auto* env = getEnv();
auto cacheFile = getCacheFileForData (data, size);
LocalRef<jbyteArray> bytes (env->NewByteArray ((jsize) size));
env->SetByteArrayRegion (bytes, 0, (jsize) size, (const jbyte*) data);
typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromByteArray, bytes.get()));
typeface = GlobalRef (LocalRef<jobject>(env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
javaString (cacheFile.getFullPathName()).get())));
initialise (env);
}
void initialise (JNIEnv* const env)
{
rect = GlobalRef (env->NewObject (AndroidRect, AndroidRect.constructor, 0, 0, 0, 0));
rect = GlobalRef (LocalRef<jobject>(env->NewObject (AndroidRect, AndroidRect.constructor, 0, 0, 0, 0)));
paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality));
const LocalRef<jobject> ignored (paint.callObjectMethod (AndroidPaint.setTypeface, typeface.get()));
charArray = GlobalRef (LocalRef<jobject>((jobject) env->NewCharArray (2)));
paint.callVoidMethod (AndroidPaint.setTextSize, referenceFontSize);
const float fullAscent = std::abs (paint.callFloatMethod (AndroidPaint.ascent));
@ -199,8 +225,8 @@ public:
float getStringWidth (const String& text) override
{
JNIEnv* env = getEnv();
const int numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
jfloatArray widths = env->NewFloatArray (numChars);
auto numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
jfloatArray widths = env->NewFloatArray ((int) numChars);
const int numDone = paint.callIntMethod (AndroidPaint.getTextWidths, javaString (text).get(), widths);
@ -209,6 +235,7 @@ public:
env->DeleteLocalRef (widths);
float x = 0;
for (int i = 0; i < numDone; ++i)
x += localWidths[i];
@ -218,8 +245,8 @@ public:
void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) override
{
JNIEnv* env = getEnv();
const int numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
jfloatArray widths = env->NewFloatArray (numChars);
auto numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
jfloatArray widths = env->NewFloatArray ((int) numChars);
const int numDone = paint.callIntMethod (AndroidPaint.getTextWidths, javaString (text).get(), widths);
@ -230,8 +257,8 @@ public:
auto s = text.getCharPointer();
xOffsets.add (0);
float x = 0;
for (int i = 0; i < numDone; ++i)
{
const float local = localWidths[i];
@ -290,20 +317,56 @@ public:
#else
jchar ch1 = glyphNumber, ch2 = 0;
#endif
Rectangle<int> bounds;
auto* env = getEnv();
JNIEnv* env = getEnv();
{
LocalRef<jobject> matrix (GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits).followedBy (t)));
jobject matrix = GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits).followedBy (t));
jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, ch1, ch2, paint.get(), matrix, rect.get());
jboolean isCopy;
auto* buffer = env->GetCharArrayElements ((jcharArray) charArray.get(), &isCopy);
env->DeleteLocalRef (matrix);
buffer[0] = ch1; buffer[1] = ch2;
env->ReleaseCharArrayElements ((jcharArray) charArray.get(), buffer, 0);
const int left = env->GetIntField (rect.get(), AndroidRect.left);
const int top = env->GetIntField (rect.get(), AndroidRect.top);
const int right = env->GetIntField (rect.get(), AndroidRect.right);
const int bottom = env->GetIntField (rect.get(), AndroidRect.bottom);
LocalRef<jobject> path (env->NewObject (AndroidPath, AndroidPath.constructor));
LocalRef<jobject> boundsF (env->NewObject (AndroidRectF, AndroidRectF.constructor));
const Rectangle<int> bounds (left, top, right - left, bottom - top);
env->CallVoidMethod (paint.get(), AndroidPaint.getCharsPath, charArray.get(), 0, (ch2 != 0 ? 2 : 1), 0.0f, 0.0f, path.get());
env->CallVoidMethod (path.get(), AndroidPath.computeBounds, boundsF.get(), 1);
env->CallBooleanMethod (matrix.get(), AndroidMatrix.mapRect, boundsF.get());
env->CallVoidMethod (boundsF.get(), AndroidRectF.roundOut, rect.get());
bounds = Rectangle<int>::leftTopRightBottom (env->GetIntField (rect.get(), AndroidRect.left) - 1,
env->GetIntField (rect.get(), AndroidRect.top),
env->GetIntField (rect.get(), AndroidRect.right) + 1,
env->GetIntField (rect.get(), AndroidRect.bottom));
auto w = bounds.getWidth();
auto h = jmax (1, bounds.getHeight());
LocalRef<jobject> bitmapConfig (env->CallStaticObjectMethod (AndroidBitmapConfig, AndroidBitmapConfig.valueOf, javaString ("ARGB_8888").get()));
LocalRef<jobject> bitmap (env->CallStaticObjectMethod (AndroidBitmap, AndroidBitmap.createBitmap, w, h, bitmapConfig.get()));
LocalRef<jobject> canvas (env->NewObject (AndroidCanvas, AndroidCanvas.create, bitmap.get()));
env->CallBooleanMethod (matrix.get(), AndroidMatrix.postTranslate, bounds.getX() * -1.0f, bounds.getY() * -1.0f);
env->CallVoidMethod (canvas.get(), AndroidCanvas.setMatrix, matrix.get());
env->CallVoidMethod (canvas.get(), AndroidCanvas.drawPath, path.get(), paint.get());
int requiredRenderArraySize = w * h;
if (requiredRenderArraySize > lastCachedRenderArraySize)
{
cachedRenderArray = GlobalRef (LocalRef<jobject> ((jobject) env->NewIntArray (requiredRenderArraySize)));
lastCachedRenderArraySize = requiredRenderArraySize;
}
env->CallVoidMethod (bitmap.get(), AndroidBitmap.getPixels, cachedRenderArray.get(), 0, w, 0, 0, w, h);
env->CallVoidMethod (bitmap.get(), AndroidBitmap.recycle);
}
EdgeTable* et = nullptr;
@ -311,10 +374,10 @@ public:
{
et = new EdgeTable (bounds);
jint* const maskDataElements = env->GetIntArrayElements (maskData, 0);
jint* const maskDataElements = env->GetIntArrayElements ((jintArray) cachedRenderArray.get(), 0);
const jint* mask = maskDataElements;
for (int y = top; y < bottom; ++y)
for (int y = bounds.getY(); y < bounds.getBottom(); ++y)
{
#if JUCE_LITTLE_ENDIAN
const uint8* const lineBytes = ((const uint8*) mask) + 3;
@ -322,19 +385,19 @@ public:
const uint8* const lineBytes = (const uint8*) mask;
#endif
et->clipLineToMask (left, y, lineBytes, 4, bounds.getWidth());
et->clipLineToMask (bounds.getX(), y, lineBytes, 4, bounds.getWidth());
mask += bounds.getWidth();
}
env->ReleaseIntArrayElements (maskData, maskDataElements, 0);
env->ReleaseIntArrayElements ((jintArray) cachedRenderArray.get(), maskDataElements, 0);
}
env->DeleteLocalRef (maskData);
return et;
}
GlobalRef typeface, paint, rect;
GlobalRef typeface, paint, rect, charArray, cachedRenderArray;
float ascent, descent, heightToPointsFactor;
int lastCachedRenderArraySize = -1;
private:
static File findFontFile (const String& family,
@ -372,6 +435,92 @@ private:
return File (path + ".ttf");
}
static LocalRef<jobject> getTypefaceFromAsset (const String& typefaceName)
{
auto* env = getEnv();
LocalRef<jobject> assetManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getAssets));
if (assetManager == nullptr)
return LocalRef<jobject>();
auto assetTypeface = env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromAsset, assetManager.get(),
javaString ("fonts/" + typefaceName).get());
// this may throw
if (env->ExceptionCheck() != 0)
{
env->ExceptionClear();
return LocalRef<jobject>();
}
return LocalRef<jobject> (assetTypeface);
}
static File getCacheDirectory()
{
static File result = [] ()
{
auto appContext = getAppContext();
if (appContext != nullptr)
{
auto* env = getEnv();
LocalRef<jobject> cacheFile (env->CallObjectMethod (appContext.get(), AndroidContext.getCacheDir));
LocalRef<jstring> jPath ((jstring) env->CallObjectMethod (cacheFile.get(), JavaFile.getAbsolutePath));
return File (juceString (env, jPath.get()));
}
jassertfalse;
return File();
} ();
return result;
}
static HashMap<String, File>& getInMemoryFontCache()
{
static HashMap<String, File> cache;
return cache;
}
static File getCacheFileForData (const void* data, size_t size)
{
static CriticalSection cs;
JNIEnv* const env = getEnv();
String key;
{
LocalRef<jobject> digest (env->CallStaticObjectMethod (JavaMessageDigest, JavaMessageDigest.getInstance, javaString("MD5").get()));
LocalRef<jbyteArray> bytes(env->NewByteArray(size));
jboolean ignore;
auto* jbytes = env->GetByteArrayElements(bytes.get(), &ignore);
memcpy(jbytes, data, size);
env->ReleaseByteArrayElements(bytes.get(), jbytes, 0);
env->CallVoidMethod(digest.get(), JavaMessageDigest.update, bytes.get());
LocalRef<jbyteArray> result((jbyteArray) env->CallObjectMethod(digest.get(), JavaMessageDigest.digest));
auto* md5Bytes = env->GetByteArrayElements(result.get(), &ignore);
key = String::toHexString(md5Bytes, env->GetArrayLength(result.get()), 0);
env->ReleaseByteArrayElements(result.get(), md5Bytes, 0);
}
ScopedLock lock (cs);
auto& mapEntry = getInMemoryFontCache().getReference (key);
if (mapEntry == File())
{
mapEntry = getCacheDirectory().getChildFile ("bindata_" + key);
mapEntry.replaceWithData (data, size);
}
return mapEntry;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface)
};

View File

@ -29,7 +29,7 @@ namespace juce
namespace GraphicsHelpers
{
jobject createPaint (Graphics::ResamplingQuality quality)
LocalRef<jobject> createPaint (Graphics::ResamplingQuality quality)
{
jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/
| 4 /*DITHER_FLAG*/
@ -38,12 +38,12 @@ namespace GraphicsHelpers
if (quality > Graphics::lowResamplingQuality)
constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/
return getEnv()->NewObject (AndroidPaint, AndroidPaint.constructor, constructorFlags);
return LocalRef<jobject>(getEnv()->NewObject (AndroidPaint, AndroidPaint.constructor, constructorFlags));
}
const jobject createMatrix (JNIEnv* env, const AffineTransform& t)
const LocalRef<jobject> createMatrix (JNIEnv* env, const AffineTransform& t)
{
jobject m = env->NewObject (AndroidMatrix, AndroidMatrix.constructor);
auto m = LocalRef<jobject>(env->NewObject (AndroidMatrix, AndroidMatrix.constructor));
jfloat values[9] = { t.mat00, t.mat01, t.mat02,
t.mat10, t.mat11, t.mat12,

View File

@ -27,13 +27,13 @@
namespace juce
{
struct FTLibWrapper : public ReferenceCountedObject
struct FTLibWrapper : public ReferenceCountedObject
{
FTLibWrapper() : library (0)
FTLibWrapper()
{
if (FT_Init_FreeType (&library) != 0)
{
library = 0;
library = {};
DBG ("Failed to initialize FreeType");
}
}
@ -44,7 +44,7 @@ struct FTLibWrapper : public ReferenceCountedObject
FT_Done_FreeType (library);
}
FT_Library library;
FT_Library library = {};
using Ptr = ReferenceCountedObjectPtr<FTLibWrapper>;
@ -55,18 +55,18 @@ struct FTLibWrapper : public ReferenceCountedObject
struct FTFaceWrapper : public ReferenceCountedObject
{
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex)
: face (0), library (ftLib)
: library (ftLib)
{
if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &face) != 0)
face = 0;
face = {};
}
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const void* data, size_t dataSize, int faceIndex)
: face (0), library (ftLib), savedFaceData (data, dataSize)
: library (ftLib), savedFaceData (data, dataSize)
{
if (FT_New_Memory_Face (ftLib->library, (const FT_Byte*) savedFaceData.getData(),
(FT_Long) savedFaceData.getSize(), faceIndex, &face) != 0)
face = 0;
face = {};
}
~FTFaceWrapper()
@ -75,7 +75,7 @@ struct FTFaceWrapper : public ReferenceCountedObject
FT_Done_Face (face);
}
FT_Face face;
FT_Face face = {};
FTLibWrapper::Ptr library;
MemoryBlock savedFaceData;
@ -101,7 +101,7 @@ public:
//==============================================================================
struct KnownTypeface
{
KnownTypeface (const File& f, const int index, const FTFaceWrapper& face)
KnownTypeface (const File& f, int index, const FTFaceWrapper& face)
: file (f),
family (face.face->family_name),
style (face.face->style_name),
@ -141,10 +141,10 @@ public:
FTFaceWrapper::Ptr createFace (const String& fontName, const String& fontStyle)
{
const KnownTypeface* ftFace = matchTypeface (fontName, fontStyle);
auto ftFace = matchTypeface (fontName, fontStyle);
if (ftFace == nullptr) ftFace = matchTypeface (fontName, "Regular");
if (ftFace == nullptr) ftFace = matchTypeface (fontName, String());
if (ftFace == nullptr) ftFace = matchTypeface (fontName, {});
if (ftFace != nullptr)
return createFace (ftFace->file, ftFace->faceIndex);
@ -157,8 +157,8 @@ public:
{
StringArray s;
for (int i = 0; i < faces.size(); ++i)
s.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
for (auto* face : faces)
s.addIfNotAlreadyThere (face->family);
return s;
}
@ -167,28 +167,27 @@ public:
{
int i = styles.indexOf ("Regular", true);
if (i < 0)
for (i = 0; i < styles.size(); ++i)
if (! (styles[i].containsIgnoreCase ("Bold") || styles[i].containsIgnoreCase ("Italic")))
break;
if (i >= 0)
return i;
return i;
for (i = 0; i < styles.size(); ++i)
if (! (styles[i].containsIgnoreCase ("Bold") || styles[i].containsIgnoreCase ("Italic")))
return i;
return -1;
}
StringArray findAllTypefaceStyles (const String& family) const
{
StringArray s;
for (int i = 0; i < faces.size(); ++i)
{
const KnownTypeface* const face = faces.getUnchecked(i);
for (auto* face : faces)
if (face->family == family)
s.addIfNotAlreadyThere (face->style);
}
// try to get a regular style to be first in the list
const int regular = indexOfRegularStyle (s);
auto regular = indexOfRegularStyle (s);
if (regular > 0)
s.strings.swap (0, regular);
@ -197,10 +196,9 @@ public:
void scanFontPaths (const StringArray& paths)
{
for (int i = 0; i < paths.size(); ++i)
for (auto& path : paths)
{
DirectoryIterator iter (File::getCurrentWorkingDirectory()
.getChildFile (paths[i]), true);
DirectoryIterator iter (File::getCurrentWorkingDirectory().getChildFile (path), true);
while (iter.next())
if (iter.getFile().hasFileExtension ("ttf;pfb;pcf;otf"))
@ -210,23 +208,23 @@ public:
void getMonospacedNames (StringArray& monoSpaced) const
{
for (int i = 0; i < faces.size(); ++i)
if (faces.getUnchecked(i)->isMonospaced)
monoSpaced.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
for (auto* face : faces)
if (face->isMonospaced)
monoSpaced.addIfNotAlreadyThere (face->family);
}
void getSerifNames (StringArray& serif) const
{
for (int i = 0; i < faces.size(); ++i)
if (! faces.getUnchecked(i)->isSansSerif)
serif.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
for (auto* face : faces)
if (! (face->isSansSerif || face->isMonospaced))
serif.addIfNotAlreadyThere (face->family);
}
void getSansSerifNames (StringArray& sansSerif) const
{
for (int i = 0; i < faces.size(); ++i)
if (faces.getUnchecked(i)->isSansSerif)
sansSerif.addIfNotAlreadyThere (faces.getUnchecked(i)->family);
for (auto* face : faces)
if (face->isSansSerif)
sansSerif.addIfNotAlreadyThere (face->family);
}
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FTTypefaceList)
@ -262,14 +260,10 @@ private:
const KnownTypeface* matchTypeface (const String& familyName, const String& style) const noexcept
{
for (int i = 0; i < faces.size(); ++i)
{
const KnownTypeface* const face = faces.getUnchecked(i);
for (auto* face : faces)
if (face->family == familyName
&& (face->style.equalsIgnoreCase (style) || style.isEmpty()))
return face;
}
return nullptr;
}
@ -278,8 +272,8 @@ private:
{
static const char* sansNames[] = { "Sans", "Verdana", "Arial", "Ubuntu" };
for (int i = 0; i < numElementsInArray (sansNames); ++i)
if (family.containsIgnoreCase (sansNames[i]))
for (auto* name : sansNames)
if (family.containsIgnoreCase (name))
return true;
return false;
@ -323,13 +317,13 @@ public:
{
if (faceWrapper != nullptr)
{
FT_Face face = faceWrapper->face;
const unsigned int glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character);
auto face = faceWrapper->face;
auto glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character);
if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING) == 0
&& face->glyph->format == ft_glyph_format_outline)
{
const float scale = 1.0f / (float) (face->ascender - face->descender);
auto scale = 1.0f / (float) (face->ascender - face->descender);
Path destShape;
if (getGlyphShape (destShape, face->glyph->outline, scale))
@ -350,12 +344,12 @@ public:
private:
FTFaceWrapper::Ptr faceWrapper;
bool getGlyphShape (Path& destShape, const FT_Outline& outline, const float scaleX)
bool getGlyphShape (Path& destShape, const FT_Outline& outline, float scaleX)
{
const float scaleY = -scaleX;
const short* const contours = outline.contours;
const char* const tags = outline.tags;
const FT_Vector* const points = outline.points;
auto scaleY = -scaleX;
auto* contours = outline.contours;
auto* tags = outline.tags;
auto* points = outline.points;
for (int c = 0; c < outline.n_contours; ++c)
{
@ -364,15 +358,15 @@ private:
for (int p = startPoint; p <= endPoint; ++p)
{
const float x = scaleX * points[p].x;
const float y = scaleY * points[p].y;
auto x = scaleX * points[p].x;
auto y = scaleY * points[p].y;
if (p == startPoint)
{
if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
{
float x2 = scaleX * points [endPoint].x;
float y2 = scaleY * points [endPoint].y;
auto x2 = scaleX * points [endPoint].x;
auto y2 = scaleY * points [endPoint].y;
if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
{
@ -396,8 +390,8 @@ private:
else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
{
const int nextIndex = (p == endPoint) ? startPoint : p + 1;
float x2 = scaleX * points [nextIndex].x;
float y2 = scaleY * points [nextIndex].y;
auto x2 = scaleX * points [nextIndex].x;
auto y2 = scaleY * points [nextIndex].y;
if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
{
@ -421,10 +415,10 @@ private:
|| FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
return false;
const float x2 = scaleX * points [next1].x;
const float y2 = scaleY * points [next1].y;
const float x3 = scaleX * points [next2].x;
const float y3 = scaleY * points [next2].y;
auto x2 = scaleX * points [next1].x;
auto y2 = scaleY * points [next1].y;
auto x3 = scaleX * points [next2].x;
auto y3 = scaleY * points [next2].y;
destShape.cubicTo (x, y, x2, y2, x3, y3);
p += 2;
@ -439,10 +433,10 @@ private:
void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex)
{
const float height = (float) (face->ascender - face->descender);
auto height = (float) (face->ascender - face->descender);
uint32 rightGlyphIndex;
FT_ULong rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
auto rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
while (rightGlyphIndex != 0)
{

View File

@ -27,16 +27,16 @@
namespace juce
{
static XmlElement* findFontsConfFile()
static std::unique_ptr<XmlElement> findFontsConfFile()
{
static const char* pathsToSearch[] = { "/etc/fonts/fonts.conf",
"/usr/share/fonts/fonts.conf" };
for (auto* path : pathsToSearch)
if (auto* xml = XmlDocument::parse (File (path)))
if (auto xml = parseXML (File (path)))
return xml;
return nullptr;
return {};
}
StringArray FTTypefaceList::getDefaultFontDirectories()
@ -48,9 +48,7 @@ StringArray FTTypefaceList::getDefaultFontDirectories()
if (fontDirs.isEmpty())
{
std::unique_ptr<XmlElement> fontsInfo (findFontsConfFile());
if (fontsInfo != nullptr)
if (auto fontsInfo = findFontsConfFile())
{
forEachXmlChildElementWithTagName (*fontsInfo, e, "dir")
{

View File

@ -32,7 +32,7 @@ class CoreGraphicsContext : public LowLevelGraphicsContext
{
public:
CoreGraphicsContext (CGContextRef context, float flipHeight, float targetScale);
~CoreGraphicsContext();
~CoreGraphicsContext() override;
//==============================================================================
bool isVectorDevice() const override { return false; }
@ -80,7 +80,7 @@ private:
float targetScale;
CGColorSpaceRef rgbColourSpace, greyColourSpace;
mutable Rectangle<int> lastClipRect;
mutable bool lastClipRectIsValid;
mutable bool lastClipRectIsValid = false;
struct SavedState
{
@ -92,9 +92,9 @@ private:
FillType fillType;
Font font;
CGFontRef fontRef;
CGFontRef fontRef = {};
CGAffineTransform fontTransform;
CGGradientRef gradient;
CGGradientRef gradient = {};
};
std::unique_ptr<SavedState> state;

View File

@ -27,27 +27,37 @@
namespace juce
{
//==============================================================================
class CoreGraphicsImage : public ImagePixelData
{
public:
CoreGraphicsImage (const Image::PixelFormat format, const int w, const int h, const bool clearImage)
: ImagePixelData (format, w, h), cachedImageRef (0)
CoreGraphicsImage (const Image::PixelFormat format, int w, int h, bool clearImage)
: ImagePixelData (format, w, h)
{
pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1);
lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
imageData.allocate ((size_t) lineStride * (size_t) jmax (1, height), clearImage);
auto numComponents = (size_t) lineStride * (size_t) jmax (1, height);
# if JUCE_MAC && defined (__MAC_10_14)
// This version of the SDK intermittently requires a bit of extra space
// at the end of the image data. This feels like something has gone
// wrong in Apple's code.
numComponents += (size_t) lineStride;
#endif
imageDataHolder->data.allocate (numComponents, clearImage);
CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray()
: CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate (imageData, (size_t) width, (size_t) height, 8, (size_t) lineStride,
context = CGBitmapContextCreate (imageDataHolder->data, (size_t) width, (size_t) height, 8, (size_t) lineStride,
colourSpace, getCGImageFlags (format));
CGColorSpaceRelease (colourSpace);
}
~CoreGraphicsImage()
~CoreGraphicsImage() override
{
freeCachedImageRef();
CGContextRelease (context);
@ -62,7 +72,7 @@ public:
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
{
bitmap.data = imageData + x * pixelStride + y * lineStride;
bitmap.data = imageDataHolder->data + x * pixelStride + y * lineStride;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride;
@ -76,9 +86,9 @@ public:
ImagePixelData::Ptr clone() override
{
CoreGraphicsImage* im = new CoreGraphicsImage (pixelFormat, width, height, false);
memcpy (im->imageData, imageData, (size_t) (lineStride * height));
return im;
auto im = new CoreGraphicsImage (pixelFormat, width, height, false);
memcpy (im->imageDataHolder->data, imageDataHolder->data, (size_t) (lineStride * height));
return *im;
}
ImageType* createType() const override { return new NativeImageType(); }
@ -86,9 +96,9 @@ public:
//==============================================================================
static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace)
{
CoreGraphicsImage* const cgim = dynamic_cast<CoreGraphicsImage*> (juceImage.getPixelData());
auto cgim = dynamic_cast<CoreGraphicsImage*> (juceImage.getPixelData());
if (cgim != nullptr && cgim->cachedImageRef != 0)
if (cgim != nullptr && cgim->cachedImageRef != nullptr)
{
CGImageRetain (cgim->cachedImageRef);
return cgim->cachedImageRef;
@ -97,36 +107,45 @@ public:
CGImageRef ref = createImage (juceImage, colourSpace, false);
if (cgim != nullptr)
{
CGImageRetain (ref);
cgim->cachedImageRef = ref;
}
cgim->cachedImageRef = CGImageRetain (ref);
return ref;
}
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, const bool mustOutliveSource)
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, bool mustOutliveSource)
{
const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly);
CGDataProviderRef provider;
if (mustOutliveSource)
{
CFDataRef data = CFDataCreate (0, (const UInt8*) srcData.data, (CFIndex) ((size_t) srcData.lineStride * (size_t) srcData.height));
CFDataRef data = CFDataCreate (nullptr, (const UInt8*) srcData.data, (CFIndex) ((size_t) srcData.lineStride * (size_t) srcData.height));
provider = CGDataProviderCreateWithCFData (data);
CFRelease (data);
}
else
{
provider = CGDataProviderCreateWithData (0, srcData.data, (size_t) srcData.lineStride * (size_t) srcData.height, 0);
auto* imageDataContainer = [](const Image& img) -> HeapBlockContainer::Ptr*
{
if (auto* cgim = dynamic_cast<CoreGraphicsImage*> (img.getPixelData()))
return new HeapBlockContainer::Ptr (cgim->imageDataHolder);
return nullptr;
} (juceImage);
provider = CGDataProviderCreateWithData (imageDataContainer,
srcData.data,
(size_t) srcData.lineStride * (size_t) srcData.height,
[] (void * __nullable info, const void*, size_t) { delete (HeapBlockContainer::Ptr*) info; });
}
CGImageRef imageRef = CGImageCreate ((size_t) srcData.width,
(size_t) srcData.height,
8, (size_t) srcData.pixelStride * 8,
8,
(size_t) srcData.pixelStride * 8,
(size_t) srcData.lineStride,
colourSpace, getCGImageFlags (juceImage.getFormat()), provider,
0, true, kCGRenderingIntentDefault);
nullptr, true, kCGRenderingIntentDefault);
CGDataProviderRelease (provider);
return imageRef;
@ -134,17 +153,24 @@ public:
//==============================================================================
CGContextRef context;
CGImageRef cachedImageRef;
HeapBlock<uint8> imageData;
CGImageRef cachedImageRef = {};
struct HeapBlockContainer : public ReferenceCountedObject
{
using Ptr = ReferenceCountedObjectPtr<HeapBlockContainer>;
HeapBlock<uint8> data;
};
HeapBlockContainer::Ptr imageDataHolder = new HeapBlockContainer();
int pixelStride, lineStride;
private:
void freeCachedImageRef()
{
if (cachedImageRef != 0)
if (cachedImageRef != CGImageRef())
{
CGImageRelease (cachedImageRef);
cachedImageRef = 0;
cachedImageRef = {};
}
}
@ -162,21 +188,28 @@ private:
ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
{
return new CoreGraphicsImage (format == Image::RGB ? Image::ARGB : format, width, height, clearImage);
return *new CoreGraphicsImage (format == Image::RGB ? Image::ARGB : format, width, height, clearImage);
}
//==============================================================================
CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, const float h, const float scale)
CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, float h, float scale)
: context (c),
flipHeight (h),
targetScale (scale),
lastClipRectIsValid (false),
state (new SavedState())
{
CGContextRetain (context);
CGContextSaveGState (context);
CGContextSetShouldSmoothFonts (context, true);
CGContextSetAllowsFontSmoothing (context, true);
bool enableFontSmoothing
#if JUCE_DISABLE_COREGRAPHICS_FONT_SMOOTHING
= false;
#else
= true;
#endif
CGContextSetShouldSmoothFonts (context, enableFontSmoothing);
CGContextSetAllowsFontSmoothing (context, enableFontSmoothing);
CGContextSetShouldAntialias (context, true);
CGContextSetBlendMode (context, kCGBlendModeNormal);
rgbColourSpace = CGColorSpaceCreateDeviceRGB();
@ -215,14 +248,15 @@ void CoreGraphicsContext::addTransform (const AffineTransform& transform)
float CoreGraphicsContext::getPhysicalPixelScaleFactor()
{
const CGAffineTransform t = CGContextGetCTM (context);
auto t = CGContextGetCTM (context);
return targetScale * (float) (juce_hypot (t.a, t.c) + juce_hypot (t.b, t.d)) / 2.0f;
}
bool CoreGraphicsContext::clipToRectangle (const Rectangle<int>& r)
{
CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()));
CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(),
r.getWidth(), r.getHeight()));
if (lastClipRectIsValid)
{
@ -295,10 +329,10 @@ void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const Affi
CGImageRef image = CoreGraphicsImage::createImage (singleChannelImage, greyColourSpace, true);
flip();
AffineTransform t (AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform));
auto t = AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform);
applyTransform (t);
CGRect r = convertToCGRect (sourceImage.getBounds());
auto r = convertToCGRect (sourceImage.getBounds());
CGContextClipToMask (context, r, image);
applyTransform (t.inverted());
@ -318,7 +352,7 @@ Rectangle<int> CoreGraphicsContext::getClipBounds() const
{
if (! lastClipRectIsValid)
{
CGRect bounds = CGRectIntegral (CGContextGetClipBoundingBox (context));
auto bounds = CGRectIntegral (CGContextGetClipBoundingBox (context));
lastClipRectIsValid = true;
lastClipRect.setBounds (roundToInt (bounds.origin.x),
@ -362,7 +396,7 @@ void CoreGraphicsContext::beginTransparencyLayer (float opacity)
{
saveState();
CGContextSetAlpha (context, opacity);
CGContextBeginTransparencyLayer (context, 0);
CGContextBeginTransparencyLayer (context, nullptr);
}
void CoreGraphicsContext::endTransparencyLayer()
@ -402,7 +436,7 @@ void CoreGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality q
}
//==============================================================================
void CoreGraphicsContext::fillRect (const Rectangle<int>& r, const bool replaceExistingContents)
void CoreGraphicsContext::fillRect (const Rectangle<int>& r, bool replaceExistingContents)
{
fillCGRect (CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()), replaceExistingContents);
}
@ -412,7 +446,7 @@ void CoreGraphicsContext::fillRect (const Rectangle<float>& r)
fillCGRect (CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()), false);
}
void CoreGraphicsContext::fillCGRect (const CGRect& cgRect, const bool replaceExistingContents)
void CoreGraphicsContext::fillCGRect (const CGRect& cgRect, bool replaceExistingContents)
{
if (replaceExistingContents)
{
@ -481,19 +515,21 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
drawImage (sourceImage, transform, false);
}
void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTransform& transform, const bool fillEntireClipAsTiles)
void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles)
{
const int iw = sourceImage.getWidth();
const int ih = sourceImage.getHeight();
CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace
: rgbColourSpace);
auto iw = sourceImage.getWidth();
auto ih = sourceImage.getHeight();
auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace
: rgbColourSpace;
CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, colourSpace);
CGContextSaveGState (context);
CGContextSetAlpha (context, state->fillType.getOpacity());
flip();
applyTransform (AffineTransform::verticalFlip (ih).followedBy (transform));
CGRect imageRect = CGRectMake (0, 0, iw, ih);
auto imageRect = CGRectMake (0, 0, iw, ih);
if (fillEntireClipAsTiles)
{
@ -502,21 +538,21 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
#else
// There's a bug in CGContextDrawTiledImage that makes it incredibly slow
// if it's doing a transformation - it's quicker to just draw lots of images manually
if (&CGContextDrawTiledImage != 0 && transform.isOnlyTranslation())
if (&CGContextDrawTiledImage != nullptr && transform.isOnlyTranslation())
{
CGContextDrawTiledImage (context, imageRect, image);
}
else
{
// Fallback to manually doing a tiled fill
CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context));
auto clip = CGRectIntegral (CGContextGetClipBoundingBox (context));
int x = 0, y = 0;
while (x > clip.origin.x) x -= iw;
while (y > clip.origin.y) y -= ih;
const int right = (int) (clip.origin.x + clip.size.width);
const int bottom = (int) (clip.origin.y + clip.size.height);
auto right = (int) (clip.origin.x + clip.size.width);
auto bottom = (int) (clip.origin.y + clip.size.height);
while (y < bottom)
{
@ -540,25 +576,9 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
//==============================================================================
void CoreGraphicsContext::drawLine (const Line<float>& line)
{
if (state->fillType.isColour())
{
CGContextSetLineCap (context, kCGLineCapSquare);
CGContextSetLineWidth (context, 1.0f);
CGContextSetRGBStrokeColor (context,
state->fillType.colour.getFloatRed(), state->fillType.colour.getFloatGreen(),
state->fillType.colour.getFloatBlue(), state->fillType.colour.getFloatAlpha());
CGPoint cgLine[] = { { (CGFloat) line.getStartX(), flipHeight - (CGFloat) line.getStartY() },
{ (CGFloat) line.getEndX(), flipHeight - (CGFloat) line.getEndY() } };
CGContextStrokeLineSegments (context, cgLine, 1);
}
else
{
Path p;
p.addLineSegment (line, 1.0f);
fillPath (p, AffineTransform());
}
Path p;
p.addLineSegment (line, 1.0f);
fillPath (p, {});
}
void CoreGraphicsContext::fillRectList (const RectangleList<float>& list)
@ -594,10 +614,10 @@ void CoreGraphicsContext::setFont (const Font& newFont)
{
if (state->font != newFont)
{
state->fontRef = 0;
state->fontRef = nullptr;
state->font = newFont;
if (OSXTypeface* osxTypeface = dynamic_cast<OSXTypeface*> (state->font.getTypeface()))
if (auto osxTypeface = dynamic_cast<OSXTypeface*> (state->font.getTypeface()))
{
state->fontRef = osxTypeface->fontRef;
CGContextSetFont (context, state->fontRef);
@ -617,7 +637,7 @@ const Font& CoreGraphicsContext::getFont()
void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& transform)
{
if (state->fontRef != 0 && state->fillType.isColour())
if (state->fontRef != nullptr && state->fillType.isColour())
{
#if JUCE_CLANG
#pragma clang diagnostic push
@ -628,7 +648,7 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra
{
CGContextSetTextMatrix (context, state->fontTransform); // have to set this each time, as it's not saved as part of the state
CGGlyph g = (CGGlyph) glyphNumber;
auto g = (CGGlyph) glyphNumber;
CGContextShowGlyphsAtPoint (context, transform.getTranslationX(),
flipHeight - roundToInt (transform.getTranslationY()), &g, 1);
}
@ -638,11 +658,11 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra
flip();
applyTransform (transform);
CGAffineTransform t = state->fontTransform;
auto t = state->fontTransform;
t.d = -t.d;
CGContextSetTextMatrix (context, t);
CGGlyph g = (CGGlyph) glyphNumber;
auto g = (CGGlyph) glyphNumber;
CGContextShowGlyphsAtPoint (context, 0, 0, &g, 1);
CGContextRestoreGState (context);
@ -655,7 +675,7 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra
else
{
Path p;
Font& f = state->font;
auto& f = state->font;
f.getTypeface()->getOutlineForGlyph (glyphNumber, p);
fillPath (p, AffineTransform::scale (f.getHeight() * f.getHorizontalScale(), f.getHeight())
@ -670,7 +690,7 @@ bool CoreGraphicsContext::drawTextLayout (const AttributedString& text, const Re
}
CoreGraphicsContext::SavedState::SavedState()
: font (1.0f), fontRef (0), fontTransform (CGAffineTransformIdentity), gradient (0)
: font (1.0f), fontTransform (CGAffineTransformIdentity)
{
}
@ -678,13 +698,13 @@ CoreGraphicsContext::SavedState::SavedState (const SavedState& other)
: fillType (other.fillType), font (other.font), fontRef (other.fontRef),
fontTransform (other.fontTransform), gradient (other.gradient)
{
if (gradient != 0)
if (gradient != nullptr)
CGGradientRetain (gradient);
}
CoreGraphicsContext::SavedState::~SavedState()
{
if (gradient != 0)
if (gradient != nullptr)
CGGradientRelease (gradient);
}
@ -692,24 +712,24 @@ void CoreGraphicsContext::SavedState::setFill (const FillType& newFill)
{
fillType = newFill;
if (gradient != 0)
if (gradient != nullptr)
{
CGGradientRelease (gradient);
gradient = 0;
gradient = nullptr;
}
}
static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef colourSpace)
{
const int numColours = g.getNumColours();
CGFloat* const data = (CGFloat*) alloca ((size_t) numColours * 5 * sizeof (CGFloat));
CGFloat* const locations = data;
CGFloat* const components = data + numColours;
CGFloat* comps = components;
auto numColours = g.getNumColours();
auto data = (CGFloat*) alloca ((size_t) numColours * 5 * sizeof (CGFloat));
auto locations = data;
auto components = data + numColours;
auto comps = components;
for (int i = 0; i < numColours; ++i)
{
const Colour colour (g.getColour (i));
auto colour = g.getColour (i);
*comps++ = (CGFloat) colour.getFloatRed();
*comps++ = (CGFloat) colour.getFloatGreen();
*comps++ = (CGFloat) colour.getFloatBlue();
@ -730,14 +750,14 @@ void CoreGraphicsContext::drawGradient()
applyTransform (state->fillType.transform);
CGContextSetAlpha (context, state->fillType.getOpacity());
const ColourGradient& g = *state->fillType.gradient;
auto& g = *state->fillType.gradient;
CGPoint p1 (convertToCGPoint (g.point1));
CGPoint p2 (convertToCGPoint (g.point2));
auto p1 = convertToCGPoint (g.point1);
auto p2 = convertToCGPoint (g.point2);
state->fillType.transform.transformPoints (p1.x, p1.y, p2.x, p2.y);
if (state->gradient == 0)
if (state->gradient == nullptr)
state->gradient = createGradient (g, rgbColourSpace);
if (g.isRadial)
@ -820,34 +840,43 @@ void CoreGraphicsContext::applyTransform (const AffineTransform& transform) cons
#if USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
Image juce_loadWithCoreImage (InputStream& input)
{
MemoryBlock data;
input.readIntoMemoryBlock (data, -1);
struct MemoryBlockHolder : public ReferenceCountedObject
{
using Ptr = ReferenceCountedObjectPtr<MemoryBlockHolder>;
MemoryBlock block;
};
MemoryBlockHolder::Ptr memBlockHolder = new MemoryBlockHolder();
input.readIntoMemoryBlock (memBlockHolder->block, -1);
#if JUCE_IOS
JUCE_AUTORELEASEPOOL
#endif
{
#if JUCE_IOS
if (UIImage* uiImage = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData()
length: data.getSize()
if (UIImage* uiImage = [UIImage imageWithData: [NSData dataWithBytesNoCopy: memBlockHolder->block.getData()
length: memBlockHolder->block.getSize()
freeWhenDone: NO]])
{
CGImageRef loadedImage = uiImage.CGImage;
#else
CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0);
CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0);
auto provider = CGDataProviderCreateWithData (new MemoryBlockHolder::Ptr (memBlockHolder),
memBlockHolder->block.getData(),
memBlockHolder->block.getSize(),
[] (void * __nullable info, const void*, size_t) { delete (MemoryBlockHolder::Ptr*) info; });
auto imageSource = CGImageSourceCreateWithDataProvider (provider, nullptr);
CGDataProviderRelease (provider);
if (imageSource != 0)
if (imageSource != nullptr)
{
CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0);
auto loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, nullptr);
CFRelease (imageSource);
#endif
if (loadedImage != 0)
if (loadedImage != nullptr)
{
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo (loadedImage);
auto alphaInfo = CGImageGetAlphaInfo (loadedImage);
const bool hasAlphaChan = (alphaInfo != kCGImageAlphaNone
&& alphaInfo != kCGImageAlphaNoneSkipLast
&& alphaInfo != kCGImageAlphaNoneSkipFirst);
@ -857,7 +886,7 @@ Image juce_loadWithCoreImage (InputStream& input)
(int) CGImageGetHeight (loadedImage),
hasAlphaChan));
CoreGraphicsImage* const cgImage = dynamic_cast<CoreGraphicsImage*> (image.getPixelData());
auto cgImage = dynamic_cast<CoreGraphicsImage*> (image.getPixelData());
jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used.
CGContextDrawImage (cgImage->context, convertToCGRect (image.getBounds()), loadedImage);
@ -875,20 +904,20 @@ Image juce_loadWithCoreImage (InputStream& input)
}
}
return Image();
return {};
}
#endif
Image juce_createImageFromCIImage (CIImage*, int, int);
Image juce_createImageFromCIImage (CIImage* im, int w, int h)
{
CoreGraphicsImage* cgImage = new CoreGraphicsImage (Image::ARGB, w, h, false);
auto cgImage = new CoreGraphicsImage (Image::ARGB, w, h, false);
CIContext* cic = [CIContext contextWithCGContext: cgImage->context options: nil];
[cic drawImage: im inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)];
CGContextFlush (cgImage->context);
return Image (cgImage);
return Image (*cgImage);
}
CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace,
@ -899,11 +928,11 @@ CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef
CGContextRef juce_getImageContext (const Image& image)
{
if (CoreGraphicsImage* const cgi = dynamic_cast<CoreGraphicsImage*> (image.getPixelData()))
if (auto cgi = dynamic_cast<CoreGraphicsImage*> (image.getPixelData()))
return cgi->context;
jassertfalse;
return 0;
return {};
}
#if JUCE_IOS
@ -929,8 +958,8 @@ CGContextRef juce_getImageContext (const Image& image)
auto requiredSize = NSMakeSize (image.getWidth() / scaleFactor, image.getHeight() / scaleFactor);
[im setSize: requiredSize];
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef = juce_createCoreGraphicsImage (image, colourSpace, true);
auto colourSpace = CGColorSpaceCreateDeviceRGB();
auto imageRef = juce_createCoreGraphicsImage (image, colourSpace, true);
CGColorSpaceRelease (colourSpace);
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: imageRef];

View File

@ -239,7 +239,7 @@ namespace CoreTextTypeLayout
{
extraKerning *= attr.font.getHeight();
auto numberRef = CFNumberCreate (0, kCFNumberFloatType, &extraKerning);
auto numberRef = CFNumberCreate (nullptr, kCFNumberFloatType, &extraKerning);
CFAttributedStringSetAttribute (attribString, range, kCTKernAttributeName, numberRef);
CFRelease (numberRef);
}
@ -503,7 +503,8 @@ public:
if (fontRef != nullptr)
{
#if JUCE_MAC && defined (MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
canBeUsedForLayout = CTFontManagerRegisterGraphicsFont (fontRef, nullptr);
if (SystemStats::getOperatingSystemType() >= SystemStats::OperatingSystemType::MacOSX_10_11)
canBeUsedForLayout = CTFontManagerRegisterGraphicsFont (fontRef, nullptr);
#endif
ctFontRef = CTFontCreateWithGraphicsFont (fontRef, referenceFontSize, nullptr, nullptr);
@ -540,7 +541,7 @@ public:
fontHeightToPointsFactor = referenceFontSize / ctTotalHeight;
const short zero = 0;
auto numberRef = CFNumberCreate (0, kCFNumberShortType, &zero);
auto numberRef = CFNumberCreate (nullptr, kCFNumberShortType, &zero);
CFStringRef keys[] = { kCTFontAttributeName, kCTLigatureAttributeName };
CFTypeRef values[] = { ctFontRef, numberRef };
@ -550,7 +551,7 @@ public:
CFRelease (numberRef);
}
~OSXTypeface()
~OSXTypeface() override
{
if (attributedStringAtts != nullptr)
CFRelease (attributedStringAtts);
@ -788,8 +789,8 @@ StringArray Font::findAllTypefaceStyles (const String& family)
//==============================================================================
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) { return new OSXTypeface (font); }
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size) { return new OSXTypeface (data, size); }
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) { return *new OSXTypeface (font); }
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size) { return *new OSXTypeface (data, size); }
void Typeface::scanFolderForFonts (const File&)
{

View File

@ -761,7 +761,7 @@ void Direct2DLowLevelGraphicsContext::drawImage (const Image& image, const Affin
pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
}
void Direct2DLowLevelGraphicsContext::drawLine (const Line <float>& line)
void Direct2DLowLevelGraphicsContext::drawLine (const Line<float>& line)
{
// xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform));

View File

@ -96,8 +96,6 @@ private:
Rectangle<int> bounds;
struct Pimpl;
friend struct Pimpl;
friend struct ContainerDeletePolicy<Pimpl>;
std::unique_ptr<Pimpl> pimpl;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DLowLevelGraphicsContext)

View File

@ -36,9 +36,7 @@ namespace DirectWriteTypeLayout
CustomDirectWriteTextRenderer (IDWriteFontCollection& fonts, const AttributedString& as)
: ComBaseClassHelper<IDWriteTextRenderer> (0),
attributedString (as),
fontCollection (fonts),
currentLine (-1),
lastOriginY (-10000.0f)
fontCollection (fonts)
{
}
@ -89,7 +87,7 @@ namespace DirectWriteTypeLayout
DWRITE_GLYPH_RUN const* glyphRun, DWRITE_GLYPH_RUN_DESCRIPTION const* runDescription,
IUnknown* clientDrawingEffect) override
{
TextLayout* const layout = static_cast<TextLayout*> (clientDrawingContext);
auto layout = static_cast<TextLayout*> (clientDrawingContext);
if (! (baselineOriginY >= -1.0e10f && baselineOriginY <= 1.0e10f))
baselineOriginY = 0; // DirectWrite sometimes sends NaNs in this parameter
@ -102,14 +100,14 @@ namespace DirectWriteTypeLayout
if (currentLine >= layout->getNumLines())
{
jassert (currentLine == layout->getNumLines());
TextLayout::Line* const line = new TextLayout::Line();
auto line = new TextLayout::Line();
layout->addLine (line);
line->lineOrigin = Point<float> (baselineOriginX, baselineOriginY);
}
}
TextLayout::Line& glyphLine = layout->getLine (currentLine);
auto& glyphLine = layout->getLine (currentLine);
DWRITE_FONT_METRICS dwFontMetrics;
glyphRun->fontFace->GetMetrics (&dwFontMetrics);
@ -117,27 +115,27 @@ namespace DirectWriteTypeLayout
glyphLine.ascent = jmax (glyphLine.ascent, scaledFontSize (dwFontMetrics.ascent, dwFontMetrics, *glyphRun));
glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, *glyphRun));
TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition,
runDescription->textPosition + runDescription->stringLength),
glyphRun->glyphCount);
auto glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition,
runDescription->textPosition + runDescription->stringLength),
glyphRun->glyphCount);
glyphLine.runs.add (glyphRunLayout);
glyphRun->fontFace->GetMetrics (&dwFontMetrics);
const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent);
const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight;
auto totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent);
auto fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight;
glyphRunLayout->font = getFontForRun (*glyphRun, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect));
const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin);
float x = baselineOriginX - lineOrigin.x;
auto lineOrigin = layout->getLine (currentLine).lineOrigin;
auto x = baselineOriginX - lineOrigin.x;
const float extraKerning = glyphRunLayout->font.getExtraKerningFactor()
* glyphRunLayout->font.getHeight();
auto extraKerning = glyphRunLayout->font.getExtraKerningFactor()
* glyphRunLayout->font.getHeight();
for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
{
const float advance = glyphRun->glyphAdvances[i];
auto advance = glyphRun->glyphAdvances[i];
if ((glyphRun->bidiLevel & 1) != 0)
x -= advance + extraKerning; // RTL text
@ -156,8 +154,8 @@ namespace DirectWriteTypeLayout
private:
const AttributedString& attributedString;
IDWriteFontCollection& fontCollection;
int currentLine;
float lastOriginY;
int currentLine = -1;
float lastOriginY = -10000.0f;
static float scaledFontSize (int n, const DWRITE_FONT_METRICS& metrics, const DWRITE_GLYPH_RUN& glyphRun) noexcept
{
@ -177,15 +175,15 @@ namespace DirectWriteTypeLayout
{
for (int i = 0; i < attributedString.getNumAttributes(); ++i)
{
const Font& font = attributedString.getAttribute(i).font;
auto& font = attributedString.getAttribute(i).font;
if (WindowsDirectWriteTypeface* wt = dynamic_cast<WindowsDirectWriteTypeface*> (font.getTypeface()))
if (auto* wt = dynamic_cast<WindowsDirectWriteTypeface*> (font.getTypeface()))
if (wt->getIDWriteFontFace() == glyphRun.fontFace)
return font.withHeight (fontHeight);
}
ComSmartPtr<IDWriteFont> dwFont;
HRESULT hr = fontCollection.GetFontFromFontFace (glyphRun.fontFace, dwFont.resetAndGetPointerAddress());
auto hr = fontCollection.GetFontFromFontFace (glyphRun.fontFace, dwFont.resetAndGetPointerAddress());
jassert (dwFont != nullptr);
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
@ -261,7 +259,7 @@ namespace DirectWriteTypeLayout
range.length = jmin (attr.range.getLength(), textLen - attr.range.getStart());
{
const String familyName (FontStyleHelpers::getConcreteFamilyName (attr.font));
auto familyName = FontStyleHelpers::getConcreteFamilyName (attr.font);
BOOL fontFound = false;
uint32 fontIndex;
@ -271,7 +269,7 @@ namespace DirectWriteTypeLayout
fontIndex = 0;
ComSmartPtr<IDWriteFontFamily> fontFamily;
HRESULT hr = fontCollection.GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress());
auto hr = fontCollection.GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress());
ComSmartPtr<IDWriteFont> dwFont;
uint32 fontFacesCount = 0;
@ -290,12 +288,12 @@ namespace DirectWriteTypeLayout
textLayout.SetFontStretch (dwFont->GetStretch(), range);
textLayout.SetFontStyle (dwFont->GetStyle(), range);
const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);
auto fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);
textLayout.SetFontSize (attr.font.getHeight() * fontHeightToEmSizeFactor, range);
}
{
const Colour col (attr.colour);
auto col = attr.colour;
ComSmartPtr<ID2D1SolidColorBrush> d2dBrush;
renderTarget.CreateSolidColorBrush (D2D1::ColorF (col.getFloatRed(),
col.getFloatGreen(),
@ -308,7 +306,7 @@ namespace DirectWriteTypeLayout
}
}
bool setupLayout (const AttributedString& text, const float maxWidth, const float maxHeight,
bool setupLayout (const AttributedString& text, float maxWidth, float maxHeight,
ID2D1RenderTarget& renderTarget, IDWriteFactory& directWriteFactory,
IDWriteFontCollection& fontCollection, ComSmartPtr<IDWriteTextLayout>& textLayout)
{
@ -324,14 +322,14 @@ namespace DirectWriteTypeLayout
fontIndex = 0;
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
HRESULT hr = fontCollection.GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());
auto hr = fontCollection.GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());
ComSmartPtr<IDWriteFont> dwFont;
hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL,
dwFont.resetAndGetPointerAddress());
jassert (dwFont != nullptr);
const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);
auto defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);
ComSmartPtr<IDWriteTextFormat> dwTextFormat;
hr = directWriteFactory.CreateTextFormat (defaultFont.getTypefaceName().toWideCharPointer(), &fontCollection,
@ -348,7 +346,7 @@ namespace DirectWriteTypeLayout
hr = dwTextFormat->SetTrimming (&trimming, trimmingSign);
}
const int textLen = text.getText().length();
auto textLen = text.getText().length();
hr = directWriteFactory.CreateTextLayout (text.getText().toWideCharPointer(), textLen, dwTextFormat,
maxWidth, maxHeight, textLayout.resetAndGetPointerAddress());
@ -356,7 +354,7 @@ namespace DirectWriteTypeLayout
if (FAILED (hr) || textLayout == nullptr)
return false;
const int numAttributes = text.getNumAttributes();
auto numAttributes = text.getNumAttributes();
for (int i = 0; i < numAttributes; ++i)
addAttributedRange (text.getAttribute (i), *textLayout, textLen, renderTarget, fontCollection);
@ -376,7 +374,7 @@ namespace DirectWriteTypeLayout
return;
UINT32 actualLineCount = 0;
HRESULT hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount);
auto hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount);
layout.ensureStorageAllocated (actualLineCount);
@ -388,13 +386,13 @@ namespace DirectWriteTypeLayout
HeapBlock<DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount);
hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount);
int lastLocation = 0;
const int numLines = jmin ((int) actualLineCount, layout.getNumLines());
auto numLines = jmin ((int) actualLineCount, layout.getNumLines());
float yAdjustment = 0;
const float extraLineSpacing = text.getLineSpacing();
auto extraLineSpacing = text.getLineSpacing();
for (int i = 0; i < numLines; ++i)
{
TextLayout::Line& line = layout.getLine (i);
auto& line = layout.getLine (i);
line.stringRange = Range<int> (lastLocation, (int) lastLocation + dwLineMetrics[i].length);
line.lineOrigin.y += yAdjustment;
yAdjustment += extraLineSpacing;
@ -422,7 +420,7 @@ namespace DirectWriteTypeLayout
static bool canAllTypefacesBeUsedInLayout (const AttributedString& text)
{
const int numCharacterAttributes = text.getNumAttributes();
auto numCharacterAttributes = text.getNumAttributes();
for (int i = 0; i < numCharacterAttributes; ++i)
if (dynamic_cast<WindowsDirectWriteTypeface*> (text.getAttribute(i).font.getTypeface()) == nullptr)

View File

@ -36,7 +36,8 @@ namespace
uint32 index = 0;
BOOL exists = false;
HRESULT hr = names->FindLocaleName (L"en-us", &index, &exists);
auto hr = names->FindLocaleName (L"en-us", &index, &exists);
if (! exists)
index = 0;
@ -53,7 +54,7 @@ namespace
{
jassert (family != nullptr);
ComSmartPtr<IDWriteLocalizedStrings> familyNames;
HRESULT hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
auto hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
jassert (SUCCEEDED (hr)); ignoreUnused (hr);
return getLocalisedName (familyNames);
}
@ -62,7 +63,7 @@ namespace
{
jassert (font != nullptr);
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
HRESULT hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
auto hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
jassert (SUCCEEDED (hr)); ignoreUnused (hr);
return getLocalisedName (faceNames);
}
@ -106,12 +107,12 @@ public:
if (d2dFactory != nullptr)
{
D2D1_RENDER_TARGET_PROPERTIES d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE,
D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0, 0,
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
D2D1_FEATURE_LEVEL_DEFAULT);
auto d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE,
D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0, 0,
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
D2D1_FEATURE_LEVEL_DEFAULT);
d2dFactory->CreateDCRenderTarget (&d2dRTProp, directWriteRenderTarget.resetAndGetPointerAddress());
}
@ -142,14 +143,14 @@ class WindowsDirectWriteTypeface : public Typeface
{
public:
WindowsDirectWriteTypeface (const Font& font, IDWriteFontCollection* fontCollection)
: Typeface (font.getTypefaceName(), font.getTypefaceStyle()),
unitsToHeightScaleFactor (1.0f), heightToPointsFactor (1.0f), ascent (0.0f)
: Typeface (font.getTypefaceName(), font.getTypefaceStyle())
{
jassert (fontCollection != nullptr);
BOOL fontFound = false;
uint32 fontIndex = 0;
HRESULT hr = fontCollection->FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound);
auto hr = fontCollection->FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound);
if (! fontFound)
fontIndex = 0;
@ -190,18 +191,18 @@ public:
designUnitsPerEm = dwFontMetrics.designUnitsPerEm;
ascent = std::abs ((float) dwFontMetrics.ascent);
const float totalSize = ascent + std::abs ((float) dwFontMetrics.descent);
auto totalSize = ascent + std::abs ((float) dwFontMetrics.descent);
ascent /= totalSize;
unitsToHeightScaleFactor = designUnitsPerEm / totalSize;
HDC tempDC = GetDC (0);
float dpi = (GetDeviceCaps (tempDC, LOGPIXELSX) + GetDeviceCaps (tempDC, LOGPIXELSY)) / 2.0f;
auto tempDC = GetDC (0);
auto dpi = (GetDeviceCaps (tempDC, LOGPIXELSX) + GetDeviceCaps (tempDC, LOGPIXELSY)) / 2.0f;
heightToPointsFactor = (dpi / GetDeviceCaps (tempDC, LOGPIXELSY)) * unitsToHeightScaleFactor;
ReleaseDC (0, tempDC);
const float pathAscent = (1024.0f * dwFontMetrics.ascent) / designUnitsPerEm;
const float pathDescent = (1024.0f * dwFontMetrics.descent) / designUnitsPerEm;
const float pathScale = 1.0f / (std::abs (pathAscent) + std::abs (pathDescent));
auto pathAscent = (1024.0f * dwFontMetrics.ascent) / designUnitsPerEm;
auto pathDescent = (1024.0f * dwFontMetrics.descent) / designUnitsPerEm;
auto pathScale = 1.0f / (std::abs (pathAscent) + std::abs (pathDescent));
pathTransform = AffineTransform::scale (pathScale);
}
}
@ -214,8 +215,8 @@ public:
float getStringWidth (const String& text)
{
const CharPointer_UTF32 textUTF32 (text.toUTF32());
const size_t len = textUTF32.length();
auto textUTF32 = text.toUTF32();
auto len = textUTF32.length();
HeapBlock<UINT16> glyphIndices (len);
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
@ -224,6 +225,7 @@ public:
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
float x = 0;
for (size_t i = 0; i < len; ++i)
x += (float) dwGlyphMetrics[i].advanceWidth / designUnitsPerEm;
@ -234,8 +236,8 @@ public:
{
xOffsets.add (0);
const CharPointer_UTF32 textUTF32 (text.toUTF32());
const size_t len = textUTF32.length();
auto textUTF32 = text.toUTF32();
auto len = textUTF32.length();
HeapBlock<UINT16> glyphIndices (len);
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
@ -243,6 +245,7 @@ public:
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
float x = 0;
for (size_t i = 0; i < len; ++i)
{
x += (float) dwGlyphMetrics[i].advanceWidth / designUnitsPerEm;
@ -254,10 +257,11 @@ public:
bool getOutlineForGlyph (int glyphNumber, Path& path)
{
jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
UINT16 glyphIndex = (UINT16) glyphNumber;
auto glyphIndex = (UINT16) glyphNumber;
ComSmartPtr<PathGeometrySink> pathGeometrySink (new PathGeometrySink());
dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr, 1, false, false, pathGeometrySink);
dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr,
1, false, false, pathGeometrySink);
path = pathGeometrySink->path;
if (! pathTransform.isIdentity())
@ -273,8 +277,8 @@ public:
private:
SharedResourcePointer<Direct2DFactories> factories;
ComSmartPtr<IDWriteFontFace> dwFontFace;
float unitsToHeightScaleFactor, heightToPointsFactor, ascent;
int designUnitsPerEm;
float unitsToHeightScaleFactor = 1.0f, heightToPointsFactor = 1.0f, ascent = 0;
int designUnitsPerEm = 0;
AffineTransform pathTransform;
struct PathGeometrySink : public ComBaseClassHelper<IDWriteGeometrySink>

View File

@ -63,14 +63,14 @@ namespace TTFNameExtractor
const int64 directoryOffset, const int64 offsetOfStringStorage)
{
String result;
const int64 oldPos = input.getPosition();
auto oldPos = input.getPosition();
input.setPosition (directoryOffset + offsetOfStringStorage + ByteOrder::swapIfLittleEndian (nameRecord.offsetFromStorageArea));
const int stringLength = (int) ByteOrder::swapIfLittleEndian (nameRecord.stringLength);
const int platformID = ByteOrder::swapIfLittleEndian (nameRecord.platformID);
auto stringLength = (int) ByteOrder::swapIfLittleEndian (nameRecord.stringLength);
auto platformID = ByteOrder::swapIfLittleEndian (nameRecord.platformID);
if (platformID == 0 || platformID == 3)
{
const int numChars = stringLength / 2 + 1;
auto numChars = stringLength / 2 + 1;
HeapBlock<uint16> buffer;
buffer.calloc (numChars + 1);
input.read (buffer, stringLength);
@ -165,10 +165,8 @@ namespace FontEnumerators
const String fontName (lpelfe->elfLogFont.lfFaceName);
fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
HDC dc = CreateCompatibleDC (0);
EnumFontFamiliesEx (dc, &lf,
(FONTENUMPROCW) &fontEnum2,
lParam, 0);
auto dc = CreateCompatibleDC (0);
EnumFontFamiliesEx (dc, &lf, (FONTENUMPROCW) &fontEnum2, lParam, 0);
DeleteDC (dc);
}
@ -191,7 +189,7 @@ StringArray Font::findAllTypefaceNames()
for (uint32 i = 0; i < fontFamilyCount; ++i)
{
HRESULT hr = factories->systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress());
auto hr = factories->systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress());
if (SUCCEEDED (hr))
results.addIfNotAlreadyThere (getFontFamilyName (fontFamily));
@ -200,7 +198,7 @@ StringArray Font::findAllTypefaceNames()
else
#endif
{
HDC dc = CreateCompatibleDC (0);
auto dc = CreateCompatibleDC (0);
{
LOGFONTW lf = { 0 };
@ -237,7 +235,8 @@ StringArray Font::findAllTypefaceStyles (const String& family)
{
BOOL fontFound = false;
uint32 fontIndex = 0;
HRESULT hr = factories->systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound);
auto hr = factories->systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound);
if (! fontFound)
fontIndex = 0;
@ -302,7 +301,7 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
static DefaultFontNames defaultNames;
Font newFont (font);
const String& faceName = font.getTypefaceName();
auto& faceName = font.getTypefaceName();
if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans);
else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif);
@ -318,22 +317,14 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
class WindowsTypeface : public Typeface
{
public:
WindowsTypeface (const Font& font)
: Typeface (font.getTypefaceName(), font.getTypefaceStyle()),
fontH (0), previousFontH (0),
dc (CreateCompatibleDC (0)), memoryFont (0),
ascent (1.0f), heightToPointsFactor (1.0f),
defaultGlyph (-1)
WindowsTypeface (const Font& font) : Typeface (font.getTypefaceName(),
font.getTypefaceStyle())
{
loadFont();
}
WindowsTypeface (const void* data, size_t dataSize)
: Typeface (String(), String()),
fontH (0), previousFontH (0),
dc (CreateCompatibleDC (0)), memoryFont (0),
ascent (1.0f), heightToPointsFactor (1.0f),
defaultGlyph (-1)
: Typeface (String(), String())
{
DWORD numInstalled = 0;
memoryFont = AddFontMemResourceEx (const_cast<void*> (data), (DWORD) dataSize,
@ -362,8 +353,8 @@ public:
float getStringWidth (const String& text)
{
const CharPointer_UTF16 utf16 (text.toUTF16());
const size_t numChars = utf16.length();
auto utf16 = text.toUTF16();
auto numChars = utf16.length();
HeapBlock<uint16> results (numChars);
float x = 0;
@ -377,10 +368,10 @@ public:
return x;
}
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
{
const CharPointer_UTF16 utf16 (text.toUTF16());
const size_t numChars = utf16.length();
auto utf16 = text.toUTF16();
auto numChars = utf16.length();
HeapBlock<uint16> results (numChars);
float x = 0;
@ -408,8 +399,8 @@ public:
GLYPHMETRICS gm;
// (although GetGlyphOutline returns a DWORD, it may be -1 on failure, so treat it as signed int..)
const int bufSize = (int) GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX,
&gm, 0, 0, &identityMatrix);
auto bufSize = (int) GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX,
&gm, 0, 0, &identityMatrix);
if (bufSize > 0)
{
@ -417,18 +408,18 @@ public:
GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm,
bufSize, data, &identityMatrix);
const TTPOLYGONHEADER* pheader = reinterpret_cast<TTPOLYGONHEADER*> (data.getData());
auto pheader = reinterpret_cast<const TTPOLYGONHEADER*> (data.getData());
const float scaleX = 1.0f / tm.tmHeight;
const float scaleY = -scaleX;
auto scaleX = 1.0f / tm.tmHeight;
auto scaleY = -scaleX;
while ((char*) pheader < data + bufSize)
{
glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value,
scaleY * pheader->pfxStart.y.value);
const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
const char* const curveEnd = ((const char*) pheader) + pheader->cb;
auto curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
auto curveEnd = ((const char*) pheader) + pheader->cb;
while ((const char*) curve < curveEnd)
{
@ -442,10 +433,10 @@ public:
{
for (int i = 0; i < curve->cpfx - 1; ++i)
{
const float x2 = scaleX * curve->apfx[i].x.value;
const float y2 = scaleY * curve->apfx[i].y.value;
float x3 = scaleX * curve->apfx[i + 1].x.value;
float y3 = scaleY * curve->apfx[i + 1].y.value;
auto x2 = scaleX * curve->apfx[i].x.value;
auto y2 = scaleY * curve->apfx[i].y.value;
auto x3 = scaleX * curve->apfx[i + 1].x.value;
auto y3 = scaleY * curve->apfx[i + 1].y.value;
if (i < curve->cpfx - 2)
{
@ -471,32 +462,19 @@ public:
private:
static const MAT2 identityMatrix;
HFONT fontH;
HGDIOBJ previousFontH;
HDC dc;
HFONT fontH = {};
HGDIOBJ previousFontH = {};
HDC dc { CreateCompatibleDC (0) };
TEXTMETRIC tm;
HANDLE memoryFont;
float ascent, heightToPointsFactor;
int defaultGlyph, heightInPoints;
HANDLE memoryFont = {};
float ascent = 1.0f, heightToPointsFactor = 1.0f;
int defaultGlyph = -1, heightInPoints = 0;
std::unordered_map<uint64, float> kerningPairs;
struct KerningPair
static uint64 kerningPairIndex (int glyph1, int glyph2)
{
int glyph1, glyph2;
float kerning;
bool operator== (const KerningPair& other) const noexcept
{
return glyph1 == other.glyph1 && glyph2 == other.glyph2;
}
bool operator< (const KerningPair& other) const noexcept
{
return glyph1 < other.glyph1
|| (glyph1 == other.glyph1 && glyph2 < other.glyph2);
}
};
SortedSet<KerningPair> kerningPairs;
return (((uint64) (uint32) glyph1) << 32) | (uint64) (uint32) glyph2;
}
void loadFont()
{
@ -514,15 +492,15 @@ private:
lf.lfHeight = -256;
name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
HFONT standardSizedFont = CreateFontIndirect (&lf);
auto standardSizedFont = CreateFontIndirect (&lf);
if (standardSizedFont != 0)
{
if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0)
{
fontH = standardSizedFont;
OUTLINETEXTMETRIC otm;
if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
{
heightInPoints = otm.otmEMSquare;
@ -537,41 +515,42 @@ private:
if (GetTextMetrics (dc, &tm))
{
float dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0f;
auto dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0f;
heightToPointsFactor = (dpi / GetDeviceCaps (dc, LOGPIXELSY)) * heightInPoints / (float) tm.tmHeight;
ascent = tm.tmAscent / (float) tm.tmHeight;
defaultGlyph = getGlyphForChar (dc, tm.tmDefaultChar);
createKerningPairs (dc, (float) tm.tmHeight);
std::unordered_map<int, int> glyphsForChars;
defaultGlyph = getGlyphForChar (dc, glyphsForChars, tm.tmDefaultChar);
createKerningPairs (dc, glyphsForChars, (float) tm.tmHeight);
}
}
void createKerningPairs (HDC hdc, const float height)
void createKerningPairs (HDC hdc, std::unordered_map<int, int>& glyphsForChars, float height)
{
HeapBlock<KERNINGPAIR> rawKerning;
const DWORD numKPs = GetKerningPairs (hdc, 0, 0);
auto numKPs = GetKerningPairs (hdc, 0, 0);
rawKerning.calloc (numKPs);
GetKerningPairs (hdc, numKPs, rawKerning);
kerningPairs.ensureStorageAllocated ((int) numKPs);
std::unordered_map<int, int> widthsForGlyphs;
for (DWORD i = 0; i < numKPs; ++i)
{
KerningPair kp;
kp.glyph1 = getGlyphForChar (hdc, rawKerning[i].wFirst);
kp.glyph2 = getGlyphForChar (hdc, rawKerning[i].wSecond);
auto glyph1 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wFirst);
auto glyph2 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wSecond);
auto standardWidth = getGlyphWidth (hdc, widthsForGlyphs, glyph1);
const int standardWidth = getGlyphWidth (hdc, kp.glyph1);
kp.kerning = (standardWidth + rawKerning[i].iKernAmount) / height;
kerningPairs.add (kp);
kp.glyph2 = -1; // add another entry for the standard width version..
kp.kerning = standardWidth / height;
kerningPairs.add (kp);
kerningPairs[kerningPairIndex (glyph1, glyph2)] = (standardWidth + rawKerning[i].iKernAmount) / height;
kerningPairs[kerningPairIndex (glyph1, -1)] = standardWidth / height;
}
}
static int getGlyphForChar (HDC dc, juce_wchar character)
static int getGlyphForChar (HDC dc, std::unordered_map<int, int>& cache, juce_wchar character)
{
auto existing = cache.find ((int) character);
if (existing != cache.end())
return existing->second;
const WCHAR charToTest[] = { (WCHAR) character, 0 };
WORD index = 0;
@ -579,9 +558,22 @@ private:
|| index == 0xffff)
return -1;
cache[(int) character] = index;
return index;
}
static int getGlyphWidth (HDC dc, std::unordered_map<int, int>& cache, int glyphNumber)
{
auto existing = cache.find (glyphNumber);
if (existing != cache.end())
return existing->second;
auto width = getGlyphWidth (dc, glyphNumber);
cache[glyphNumber] = width;
return width;
}
static int getGlyphWidth (HDC dc, int glyphNumber)
{
GLYPHMETRICS gm;
@ -590,28 +582,21 @@ private:
return gm.gmCellIncX;
}
float getKerning (HDC hdc, const int glyph1, const int glyph2)
float getKerning (HDC hdc, int glyph1, int glyph2)
{
KerningPair kp;
kp.glyph1 = glyph1;
kp.glyph2 = glyph2;
int index = kerningPairs.indexOf (kp);
auto pair = kerningPairs.find (kerningPairIndex (glyph1, glyph2));
if (index < 0)
{
kp.glyph2 = -1;
index = kerningPairs.indexOf (kp);
if (pair != kerningPairs.end())
return pair->second;
if (index < 0)
{
kp.glyph2 = -1;
kp.kerning = getGlyphWidth (hdc, kp.glyph1) / (float) tm.tmHeight;
kerningPairs.add (kp);
return kp.kerning;
}
}
auto single = kerningPairs.find (kerningPairIndex (glyph1, -1));
return kerningPairs.getReference (index).kerning;
if (single != kerningPairs.end())
return single->second;
auto width = getGlyphWidth (hdc, glyph1) / (float) tm.tmHeight;
kerningPairs[kerningPairIndex (glyph1, -1)] = width;
return width;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface)