@@ -210,6 +210,12 @@ FontFreeType::FontFreeType(bool distanceFieldEnabled /* = false */, float outlin
210210
211211FontFreeType::~FontFreeType ()
212212{
213+ AX_ASSERT (_usedBuffers.empty ());
214+
215+ for (const BufferPool& p : _availableBuffers)
216+ for (uint8_t * b : p.buffers )
217+ delete[] b;
218+
213219 if (_FTInitialized)
214220 {
215221 if (_stroker)
@@ -503,15 +509,15 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
503509
504510 if (_outlineSize > 0 && outWidth > 0 && outHeight > 0 )
505511 {
506- auto copyBitmap = new unsigned char [ outWidth * outHeight] ;
507- memcpy (copyBitmap, ret, outWidth * outHeight * sizeof (unsigned char ));
512+ uint8_t * const copyBitmap = acquireBuffer ( outWidth * outHeight) ;
513+ memcpy (copyBitmap, ret, outWidth * outHeight * sizeof (uint8_t ));
508514
509515 FT_BBox bbox;
510516 auto outlineBitmap = getGlyphBitmapWithOutline (glyphIndex, bbox);
511517 if (outlineBitmap == nullptr )
512518 {
513519 ret = nullptr ;
514- delete[] copyBitmap;
520+ releaseBuffer ( copyBitmap) ;
515521 break ;
516522 }
517523
@@ -540,7 +546,7 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
540546 {
541547 FT_Pos index, index2;
542548 auto imageSize = blendWidth * blendHeight * 2 ;
543- blendImage = new unsigned char [ imageSize] ;
549+ blendImage = acquireBuffer ( imageSize) ;
544550 memset (blendImage, 0 , imageSize);
545551
546552 auto px = outlineMinX - blendImageMinX;
@@ -573,8 +579,8 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
573579 outWidth = static_cast <int >(blendWidth);
574580 outHeight = static_cast <int >(blendHeight);
575581
576- delete[] outlineBitmap;
577- delete[] copyBitmap;
582+ releaseBuffer ( outlineBitmap) ;
583+ releaseBuffer ( copyBitmap) ;
578584 ret = blendImage;
579585 }
580586
@@ -588,6 +594,24 @@ unsigned char* FontFreeType::getGlyphBitmapByIndex(unsigned int glyphIndex,
588594 return nullptr ;
589595}
590596
597+ /* *
598+ * Put the given buffer back into the pool of buffers.
599+ */
600+ void FontFreeType::releaseBuffer (uint8_t * buffer)
601+ {
602+ const UsedBuffersMap::iterator it = _usedBuffers.find (buffer);
603+ AX_ASSERT (it != _usedBuffers.end ());
604+
605+ for (BufferPool& p : _availableBuffers)
606+ if (p.capacity == it->second )
607+ {
608+ p.buffers .emplace_back (buffer);
609+ break ;
610+ }
611+
612+ _usedBuffers.erase (it);
613+ }
614+
591615unsigned char * FontFreeType::getGlyphBitmapWithOutline (unsigned int glyphIndex, FT_BBox& bbox)
592616{
593617 unsigned char * ret = nullptr ;
@@ -607,7 +631,7 @@ unsigned char* FontFreeType::getGlyphBitmapWithOutline(unsigned int glyphIndex,
607631 int32_t rows = static_cast <int32_t >((bbox.yMax - bbox.yMin ) >> 6 );
608632
609633 FT_Bitmap bmp;
610- bmp.buffer = new unsigned char [ width * rows] ;
634+ bmp.buffer = acquireBuffer ( width * rows) ;
611635 memset (bmp.buffer , 0 , width * rows);
612636 bmp.width = (int )width;
613637 bmp.rows = (int )rows;
@@ -653,7 +677,7 @@ void FontFreeType::renderCharAt(unsigned char* dest,
653677 memcpy (dest + (iX + (iY * atlasWidth)) * 2 , bitmap + bitmap_y * 2 , bitmapWidth * 2 );
654678 ++iY;
655679 }
656- delete[] bitmap;
680+ releaseBuffer ( bitmap) ;
657681 }
658682 else
659683 {
@@ -710,4 +734,56 @@ void FontFreeType::releaseFont(std::string_view fontName)
710734 }
711735}
712736
737+ /* *
738+ * Find a buffer with a capacity larger or equal to the given size. If there is
739+ * no such buffer, a new one is created. In all cases the returned buffer is
740+ * added to the used buffers list and will have to be released via
741+ * releaseBuffer.
742+ */
743+ uint8_t * FontFreeType::acquireBuffer (size_t size)
744+ {
745+ const size_t n = _availableBuffers.size ();
746+
747+ // Index of the first pool of large enough buffers. If we could not find a
748+ // buffer for the given size, this is also the index where a new pool will
749+ // be inserted.
750+ size_t new_pool_index = n;
751+
752+ // Find the place where the best pool for our size should be.
753+ for (size_t i = 0 ; i != n; ++i)
754+ if (_availableBuffers[i].capacity >= size)
755+ {
756+ new_pool_index = i;
757+ break ;
758+ }
759+
760+ // Now search for a pool with an available buffer.
761+ for (size_t i = new_pool_index; i != n; ++i)
762+ {
763+ BufferPool& p = _availableBuffers[i];
764+
765+ // A pool with large enough buffers and an available one.
766+ if (!p.buffers .empty ())
767+ {
768+ uint8_t * const buffer = p.buffers .back ();
769+ p.buffers .pop_back ();
770+ _usedBuffers[buffer] = p.capacity ;
771+
772+ return buffer;
773+ }
774+ }
775+
776+ if ((new_pool_index == n) || (_availableBuffers[new_pool_index].capacity != size))
777+ // Either all pools have capacities smaller than the requested size, or else
778+ // We have pools with capacity larger than the requested size but none had
779+ // an available buffer. We create a new pool for the requested size so
780+ // we'll be ready to receive the buffer in releaseBuffer.
781+ _availableBuffers.emplace (_availableBuffers.begin () + new_pool_index)->capacity = size;
782+
783+ uint8_t * const buffer (new uint8_t [size]);
784+ _usedBuffers[buffer] = size;
785+
786+ return buffer;
787+ }
788+
713789} // namespace ax
0 commit comments