@@ -210,6 +210,14 @@ FontFreeType::FontFreeType(bool distanceFieldEnabled /* = false */, float outlin
210210
211211FontFreeType::~FontFreeType ()
212212{
213+ AX_ASSERT (_usedBuffers.empty ());
214+
215+ for (const BufferPool& p : _availableBuffers)
216+ {
217+ for (uint8_t * b : p.buffers )
218+ delete[] b;
219+ }
220+
213221 if (_FTInitialized)
214222 {
215223 if (_stroker)
@@ -503,15 +511,15 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
503511
504512 if (_outlineSize > 0 && outWidth > 0 && outHeight > 0 )
505513 {
506- auto copyBitmap = new unsigned char [ outWidth * outHeight] ;
507- memcpy (copyBitmap, ret, outWidth * outHeight * sizeof (unsigned char ));
514+ uint8_t * const copyBitmap = acquireBuffer ( outWidth * outHeight) ;
515+ memcpy (copyBitmap, ret, outWidth * outHeight * sizeof (uint8_t ));
508516
509517 FT_BBox bbox;
510518 auto outlineBitmap = getGlyphBitmapWithOutline (glyphIndex, bbox);
511519 if (outlineBitmap == nullptr )
512520 {
513521 ret = nullptr ;
514- delete[] copyBitmap;
522+ releaseBuffer ( copyBitmap) ;
515523 break ;
516524 }
517525
@@ -540,7 +548,7 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
540548 {
541549 FT_Pos index, index2;
542550 auto imageSize = blendWidth * blendHeight * 2 ;
543- blendImage = new unsigned char [ imageSize] ;
551+ blendImage = acquireBuffer ( imageSize) ;
544552 memset (blendImage, 0 , imageSize);
545553
546554 auto px = outlineMinX - blendImageMinX;
@@ -573,8 +581,8 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
573581 outWidth = static_cast <int >(blendWidth);
574582 outHeight = static_cast <int >(blendHeight);
575583
576- delete[] outlineBitmap;
577- delete[] copyBitmap;
584+ releaseBuffer ( outlineBitmap) ;
585+ releaseBuffer ( copyBitmap) ;
578586 ret = blendImage;
579587 }
580588
@@ -588,6 +596,26 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
588596 return nullptr ;
589597}
590598
599+ /* *
600+ * Put the given buffer back into the pool of buffers.
601+ */
602+ void FontFreeType::releaseBuffer (uint8_t * buffer)
603+ {
604+ const UsedBuffersMap::iterator it = _usedBuffers.find (buffer);
605+ AX_ASSERT (it != _usedBuffers.end ());
606+
607+ for (BufferPool& p : _availableBuffers)
608+ {
609+ if (p.capacity == it->second )
610+ {
611+ p.buffers .emplace_back (buffer);
612+ break ;
613+ }
614+ }
615+
616+ _usedBuffers.erase (it);
617+ }
618+
591619unsigned char * FontFreeType::getGlyphBitmapWithOutline (unsigned int glyphIndex, FT_BBox& bbox)
592620{
593621 unsigned char * ret = nullptr ;
@@ -607,7 +635,7 @@ unsigned char* FontFreeType::getGlyphBitmapWithOutline(unsigned int glyphIndex,
607635 int32_t rows = static_cast <int32_t >((bbox.yMax - bbox.yMin ) >> 6 );
608636
609637 FT_Bitmap bmp;
610- bmp.buffer = new unsigned char [ width * rows] ;
638+ bmp.buffer = acquireBuffer ( width * rows) ;
611639 memset (bmp.buffer , 0 , width * rows);
612640 bmp.width = (int )width;
613641 bmp.rows = (int )rows;
@@ -653,7 +681,7 @@ void FontFreeType::renderCharAt(unsigned char* dest,
653681 memcpy (dest + (iX + (iY * atlasWidth)) * 2 , bitmap + bitmap_y * 2 , bitmapWidth * 2 );
654682 ++iY;
655683 }
656- delete[] bitmap;
684+ releaseBuffer ( bitmap) ;
657685 }
658686 else
659687 {
@@ -710,4 +738,61 @@ void FontFreeType::releaseFont(std::string_view fontName)
710738 }
711739}
712740
741+ /* *
742+ * Find a buffer with a capacity larger or equal to the given size. If there is
743+ * no such buffer, a new one is created. In all cases the returned buffer is
744+ * added to the used buffers list and will have to be released via
745+ * releaseBuffer.
746+ */
747+ uint8_t * FontFreeType::acquireBuffer (size_t size)
748+ {
749+ const size_t n = _availableBuffers.size ();
750+
751+ // Index of the first pool of large enough buffers. If we could not find a
752+ // buffer for the exact given size, this is also the index where a new pool
753+ // will be inserted, since it is the first larger than the size (or the end
754+ // of the list).
755+ size_t new_pool_index = n;
756+
757+ // Find the place where the best pool for our size should be (i.e. the first
758+ // pool for buffers of capacity greater or equal to the requested size).
759+ for (size_t i = 0 ; i != n; ++i)
760+ {
761+ if (_availableBuffers[i].capacity >= size)
762+ {
763+ new_pool_index = i;
764+ break ;
765+ }
766+ }
767+
768+ // Now search for a pool with an available buffer.
769+ for (size_t i = new_pool_index; i != n; ++i)
770+ {
771+ BufferPool& p = _availableBuffers[i];
772+
773+ if (!p.buffers .empty ())
774+ {
775+ uint8_t * const buffer = p.buffers .back ();
776+ p.buffers .pop_back ();
777+ _usedBuffers[buffer] = p.capacity ;
778+
779+ return buffer;
780+ }
781+ }
782+
783+ if ((new_pool_index == n) || (_availableBuffers[new_pool_index].capacity != size))
784+ {
785+ // Either all pools have capacities smaller than the requested size, or else
786+ // We have pools with capacity larger than the requested size but none had
787+ // an available buffer. We create a new pool for the requested size so
788+ // we'll be ready to receive the buffer in releaseBuffer.
789+ _availableBuffers.emplace (_availableBuffers.begin () + new_pool_index)->capacity = size;
790+ }
791+
792+ uint8_t * const buffer (new uint8_t [size]);
793+ _usedBuffers[buffer] = size;
794+
795+ return buffer;
796+ }
797+
713798}
0 commit comments