bug 721511 - use stack-based buffers for moderate-sized glyph runs in cairo/dwrite backend. r=bas
authorJonathan Kew <jfkthame@gmail.com>
Sat, 28 Jan 2012 12:25:53 +0000
changeset 86885 f36a9b649c6b9b2ea2a9660328d92ef19f3f0120
parent 86884 a9a667cc58397d67ec297138ec0b421b0254ab59
child 86886 9393d706cb29593c5d39013a7cfa3f2df3e20f43
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs721511
milestone12.0a1
bug 721511 - use stack-based buffers for moderate-sized glyph runs in cairo/dwrite backend. r=bas
gfx/cairo/cairo/src/cairo-d2d-surface.cpp
gfx/cairo/cairo/src/cairo-dwrite-font.cpp
gfx/cairo/cairo/src/cairo-dwrite-private.h
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -3669,17 +3669,17 @@ cairo_int_status_t
 
     if (!dst->isDrawing) {
 	_cairo_d2d_flush_dependent_surfaces(dst);
     }
 
     _cairo_d2d_set_clip(dst, NULL);
     dst->rt->Flush();
 
-    DWRITE_GLYPH_RUN run;
+    AutoDWriteGlyphRun run;
     _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, scaled_font, &run, &transform);
 
     RefPtr<IDWriteGlyphRunAnalysis> analysis;
     DWRITE_MATRIX dwmat = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);
 
     RefPtr<IDWriteRenderingParams> params;
     dst->rt->GetTextRenderingParams(&params);
 
@@ -3726,19 +3726,16 @@ cairo_int_status_t
     hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
 						      1.0f,
 						      transform ? &dwmat : 0,
 						      renderMode,
 						      measureMode,
 						      0,
 						      0,
 						      &analysis);
-    delete [] run.glyphIndices;
-    delete [] run.glyphAdvances;
-    delete [] run.glyphOffsets;
     if (FAILED(hr)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     RECT bounds;
     hr = analysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1,
 					 &bounds);
     if (FAILED(hr) ||
@@ -4100,18 +4097,17 @@ static cairo_int_status_t
 
     DWRITE_MEASURING_MODE measureMode =
 	renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
 	renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
 	DWRITE_MEASURING_MODE_NATURAL;
 
     cairo_bool_t transform = FALSE;
 
-    DWRITE_GLYPH_RUN run;
-    
+    AutoDWriteGlyphRun run;
     _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
 
     D2D1::Matrix3x2F mat = _cairo_d2d_matrix_from_matrix(&dwritesf->mat);
 	
     if (transform) {
 	target_rt->SetTransform(mat);
     }
 
@@ -4136,19 +4132,16 @@ static cairo_int_status_t
 	fontArea.width = bounds.right - bounds.left;
 	fontArea.height = bounds.bottom - bounds.top;
     }
 
     RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst,
 								   source);
 
     if (!brush) {
-	delete [] run.glyphIndices;
-	delete [] run.glyphOffsets;
-	delete [] run.glyphAdvances;
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
     
     if (transform) {
 	D2D1::Matrix3x2F mat_inverse = _cairo_d2d_matrix_from_matrix(&dwritesf->mat_inverse);
 	D2D1::Matrix3x2F mat_brush;
 
 	// The brush matrix needs to be multiplied with the inverted matrix
@@ -4160,20 +4153,16 @@ static cairo_int_status_t
     }
     
     target_rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush, measureMode);
     
     if (transform) {
 	target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
     }
 
-    delete [] run.glyphIndices;
-    delete [] run.glyphOffsets;
-    delete [] run.glyphAdvances;
-
     if (target_rt.get() != dst->rt.get()) {
 	return _cairo_d2d_blend_temp_surface(dst, op, target_rt, clip, &fontArea);
     }
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
+++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
@@ -331,32 +331,31 @@ read_short(const char *buf)
 {
     return be16_to_cpu(*(unsigned short*)buf);
 }
 
 void
 _cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
 				    int num_glyphs,
 				    cairo_dwrite_scaled_font_t *scaled_font,
-				    DWRITE_GLYPH_RUN *run,
+				    AutoDWriteGlyphRun *run,
 				    cairo_bool_t *transformed)
 {
-    UINT16 *indices = new UINT16[num_glyphs];
-    FLOAT *advances = new FLOAT[num_glyphs];
-    DWRITE_GLYPH_OFFSET *offsets = new DWRITE_GLYPH_OFFSET[num_glyphs];
+    run->allocate(num_glyphs);
+
+    UINT16 *indices = const_cast<UINT16*>(run->glyphIndices);
+    FLOAT *advances = const_cast<FLOAT*>(run->glyphAdvances);
+    DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run->glyphOffsets);
 
     cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->base.font_face);
 
     run->bidiLevel = 0;
     run->fontFace = dwriteff->dwriteface;
     run->glyphCount = num_glyphs;
     run->isSideways = FALSE;
-    run->glyphIndices = indices;
-    run->glyphOffsets = offsets;
-    run->glyphAdvances = advances;
 
     if (scaled_font->mat.xy == 0 && scaled_font->mat.yx == 0 &&
 	scaled_font->mat.xx == scaled_font->base.font_matrix.xx && 
 	scaled_font->mat.yy == scaled_font->base.font_matrix.yy) {
 	// Fast route, don't actually use a transform but just
 	// set the correct font size.
 	*transformed = 0;
 
@@ -593,29 +592,27 @@ cairo_warn cairo_int_status_t
 	status = (cairo_int_status_t)_cairo_dwrite_show_glyphs_on_surface (surface, op, pattern,
 									  glyphs, num_glyphs, 
 									  (cairo_scaled_font_t*)scaled_font, NULL);
 
 	return status;
     } else {
 	cairo_dwrite_scaled_font_t *dwritesf =
 	    static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
-	UINT16 *indices = new UINT16[num_glyphs];
-	DWRITE_GLYPH_OFFSET *offsets = new DWRITE_GLYPH_OFFSET[num_glyphs];
-	FLOAT *advances = new FLOAT[num_glyphs];
 	BOOL transform = FALSE;
 
-	DWRITE_GLYPH_RUN run;
+	AutoDWriteGlyphRun run;
+	run.allocate(num_glyphs);
+        UINT16 *indices = const_cast<UINT16*>(run.glyphIndices);
+        FLOAT *advances = const_cast<FLOAT*>(run.glyphAdvances);
+        DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
+
 	run.bidiLevel = 0;
 	run.fontFace = ((cairo_dwrite_font_face_t*)dwritesf->base.font_face)->dwriteface;
-	run.glyphIndices = indices;
-	run.glyphCount = num_glyphs;
 	run.isSideways = FALSE;
-	run.glyphOffsets = offsets;
-	run.glyphAdvances = advances;
     	IDWriteGlyphRunAnalysis *analysis;
 
 	if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
 	    dwritesf->mat.xx == dwritesf->base.font_matrix.xx && 
 	    dwritesf->mat.yy == dwritesf->base.font_matrix.yy) {
 
 	    for (int i = 0; i < num_glyphs; i++) {
 		indices[i] = (WORD) glyphs[i].index;
@@ -702,19 +699,16 @@ cairo_warn cairo_int_status_t
 							       dest_x, dest_y,
 							       width, height,
 							       clip_region);
 
 	_cairo_pattern_fini (&mask.base);
 
 	analysis->Release();
 	delete [] surface;
-	delete [] indices;
-	delete [] offsets;
-	delete [] advances;
 
 	cairo_surface_destroy (&mask_surface->base);
 	*remaining_glyphs = 0;
 
 	return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
     }
 }
 
@@ -1280,19 +1274,23 @@ cairo_int_status_t
     }
 
     /* It is vital that dx values for dxy_buf are calculated from the delta of
      * _logical_ x coordinates (not user x coordinates) or else the sum of all
      * previous dx values may start to diverge from the current glyph's x
      * coordinate due to accumulated rounding error. As a result strings could
      * be painted shorter or longer than expected. */
 
-    UINT16 *indices = new UINT16[num_glyphs];
-    DWRITE_GLYPH_OFFSET *offsets = new DWRITE_GLYPH_OFFSET[num_glyphs];
-    FLOAT *advances = new FLOAT[num_glyphs];
+    AutoDWriteGlyphRun run;
+    run.allocate(num_glyphs);
+
+    UINT16 *indices = const_cast<UINT16*>(run.glyphIndices);
+    FLOAT *advances = const_cast<FLOAT*>(run.glyphAdvances);
+    DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
+
     BOOL transform = FALSE;
     /* Needed to calculate bounding box for efficient blitting */
     INT32 smallestX = INT_MAX;
     INT32 largestX = 0;
     INT32 smallestY = INT_MAX;
     INT32 largestY = 0;
     for (int i = 0; i < num_glyphs; i++) {
 	if (glyphs[i].x < smallestX) {
@@ -1338,24 +1336,19 @@ cairo_int_status_t
     }
     if (fontArea.right > dst->extents.width) {
 	fontArea.right = dst->extents.width;
     }
     if (fontArea.bottom > dst->extents.height) {
 	fontArea.bottom = dst->extents.height;
     }
 
-    DWRITE_GLYPH_RUN run;
     run.bidiLevel = 0;
     run.fontFace = dwriteff->dwriteface;
-    run.glyphIndices = indices;
-    run.glyphCount = num_glyphs;
     run.isSideways = FALSE;
-    run.glyphOffsets = offsets;
-    run.glyphAdvances = advances;
     if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
 	dwritesf->mat.xx == scaled_font->font_matrix.xx && 
 	dwritesf->mat.yy == scaled_font->font_matrix.yy) {
 
 	for (int i = 0; i < num_glyphs; i++) {
 	    indices[i] = (WORD) glyphs[i].index;
 	    // Since we will multiply by our ctm matrix later for rotation effects
 	    // and such, adjust positions by the inverse matrix now.
@@ -1419,20 +1412,16 @@ cairo_int_status_t
 							&run,
 							color,
 							dwritesf,
 							fontArea);
 #ifdef CAIRO_TRY_D2D_TO_GDI
     }
 #endif
 
-    delete [] indices;
-    delete [] offsets;
-    delete [] advances;
-
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
 #define ENHANCED_CONTRAST_REGISTRY_KEY \
     HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel"
 
 void
 DWriteFactory::CreateRenderingParams()
--- a/gfx/cairo/cairo/src/cairo-dwrite-private.h
+++ b/gfx/cairo/cairo/src/cairo-dwrite-private.h
@@ -164,27 +164,61 @@ private:
     static IDWriteRenderingParams *mForceGDIClassicRenderingParams;
     static FLOAT mGamma;
     static FLOAT mEnhancedContrast;
     static FLOAT mClearTypeLevel;
     static int mPixelGeometry;
     static int mRenderingMode;
 };
 
+class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN
+{
+    static const int kNumAutoGlyphs = 256;
+
+public:
+    AutoDWriteGlyphRun() {
+        glyphCount = 0;
+    }
+
+    ~AutoDWriteGlyphRun() {
+        if (glyphCount > kNumAutoGlyphs) {
+            delete[] glyphIndices;
+            delete[] glyphAdvances;
+            delete[] glyphOffsets;
+        }
+    }
+
+    void allocate(int aNumGlyphs) {
+        glyphCount = aNumGlyphs;
+        if (aNumGlyphs <= kNumAutoGlyphs) {
+            glyphIndices = &mAutoIndices[0];
+            glyphAdvances = &mAutoAdvances[0];
+            glyphOffsets = &mAutoOffsets[0];
+        } else {
+            glyphIndices = new UINT16[aNumGlyphs];
+            glyphAdvances = new FLOAT[aNumGlyphs];
+            glyphOffsets = new DWRITE_GLYPH_OFFSET[aNumGlyphs];
+        }
+    }
+
+private:
+    DWRITE_GLYPH_OFFSET mAutoOffsets[kNumAutoGlyphs];
+    FLOAT               mAutoAdvances[kNumAutoGlyphs];
+    UINT16              mAutoIndices[kNumAutoGlyphs];
+};
+
 /* cairo_font_face_t implementation */
 struct _cairo_dwrite_font_face {
     cairo_font_face_t base;
     IDWriteFont *font;
     IDWriteFontFace *dwriteface;
 };
 typedef struct _cairo_dwrite_font_face cairo_dwrite_font_face_t;
 
 DWRITE_MATRIX _cairo_dwrite_matrix_from_matrix(const cairo_matrix_t *matrix);
 
-// This will create a DWrite glyph run from cairo glyphs and a scaled_font.
-// It is important to note the array members of DWRITE_GLYPH_RUN should be
-// deleted by the caller.
+// This will initialize a DWrite glyph run from cairo glyphs and a scaled_font.
 void
 _cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
 				    int num_glyphs,
 				    cairo_dwrite_scaled_font_t *scaled_font,
-				    DWRITE_GLYPH_RUN *run,
+				    AutoDWriteGlyphRun *run,
 				    cairo_bool_t *transformed);