Exemple #1
0
bool GlyphLayerBevel::render(
    cairo_t*       c,
    cairo_glyph_t* glyph,
    unsigned int   width,
    unsigned int   height
) {
    if(cairo_status(c) || !glyph) return false;

    cairo_surface_t* bumpmap = cairo_image_surface_create(CAIRO_FORMAT_A8, width, height);
    cairo_t*         cr      = cairo_create(bumpmap);

    cairo_set_scaled_font(cr, cairo_get_scaled_font(c));
    cairo_glyph_path(cr, glyph, 1);
    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);

    for(double l = _bevelWidth; l > 0.0f; l -= _bevelStep) {
        cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 1.0f - (l / _bevelWidth));
        cairo_set_line_width(cr, l);
        cairo_stroke_preserve(cr);
    }

    cairo_destroy(cr);

    cairo_surface_t* lightmap = osgPairo::createEmbossedSurface(
                                    bumpmap,
                                    _azimuth,
                                    _elevation,
                                    _height,
                                    _ambient,
                                    _diffuse
                                );

    cairo_glyph_path(c, glyph, 1);
    cairo_save(c);
    cairo_clip_preserve(c);
    cairo_set_operator(c, CAIRO_OPERATOR_SOURCE);
    cairo_set_source_surface(c, lightmap, 0, 0);
    cairo_paint(c);
    cairo_set_operator(c, CAIRO_OPERATOR_SATURATE);
    cairo_set_source_rgba(c, 1.0f, 1.0f, 1.0f, 1.0f);
    cairo_paint(c);
    cairo_restore(c);

    // TODO: This is a hack! Figure out why the border is poor quality...
    cairo_set_line_width(c, 4.0);
    cairo_set_operator(c, CAIRO_OPERATOR_CLEAR);
    cairo_stroke(c);

    // cairo_surface_write_to_png(bumpmap, "bumpmap.png");
    // cairo_surface_write_to_png(lightmap, "lightmap.png");

    cairo_surface_destroy(bumpmap);
    cairo_surface_destroy(lightmap);

    return true;
}
void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint)
{
#ifdef USE_CAIRO
  PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);

  
  cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());

  if (aTransformHint) {
    cairo_matrix_t mat;
    GfxMatrixToCairoMatrix(*aTransformHint, mat);
    cairo_set_matrix(ctx, &mat);
  }

  // Convert our GlyphBuffer into an array of Cairo glyphs.
  std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
  for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
    glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
    glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
    glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
  }

  cairo_set_scaled_font(ctx, mScaledFont);
  cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

  RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
  cairo_destroy(ctx);

  cairoPath->AppendPathToBuilder(builder);
#endif
}
Exemple #3
0
bool GlyphLayerBitmap::render(
	cairo_t*       c,
	cairo_glyph_t* glyph,
	unsigned int   width,
	unsigned int   height
) {
	if(cairo_status(c) || !glyph || !_bitmap || cairo_pattern_status(_pattern)) return false;

	double bw = _bitmap->getSurfaceWidth();
	double bh = _bitmap->getSurfaceHeight();

	if(_repeatX > 1 || _repeatY > 1) cairo_pattern_set_extend(_pattern, CAIRO_EXTEND_REPEAT);
	
	else cairo_pattern_set_extend(_pattern, CAIRO_EXTEND_PAD);
	
	cairo_matrix_t matrix;

	cairo_matrix_init_scale(&matrix, bw / width * _repeatX, bh / height * _repeatY);
	cairo_pattern_set_matrix(_pattern, &matrix);

	cairo_set_source(c, _pattern);

	cairo_glyph_path(c, glyph, 1);
	cairo_fill(c);

	return true;
}
int renderTruetypeSymbolCairo(imageObj *img, double x, double y, symbolObj *symbol,
                              symbolStyleObj *s)
{
  int unicode;
  cairo_glyph_t glyph;
  cairo_text_extents_t extents;

  cairo_matrix_t trans;
  double ox,oy;
  cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img);
  cairo_renderer *r = CAIRO_RENDERER(img);
  faceCacheObj *face = getFontFace(cache,symbol->full_font_path);

  if(!face) return MS_FAILURE;

  cairo_save(r->cr);
  cairo_set_font_face(r->cr,face->face);
  cairo_set_font_size(r->cr,s->scale*96/72.0);


  msUTF8ToUniChar(symbol->character, &unicode);

  if (face->ftface->charmap &&
    face->ftface->charmap->encoding == FT_ENCODING_MS_SYMBOL)
    unicode |= 0xf000;

  glyph.index = FT_Get_Char_Index(face->ftface, unicode);
  glyph.x=0;
  glyph.y=0;
  cairo_glyph_extents(r->cr,&glyph,1,&extents);
  ox=extents.x_bearing+extents.width/2.;
  oy=extents.y_bearing+extents.height/2.;



  cairo_matrix_init_rotate(&trans,-s->rotation);

  cairo_matrix_transform_point(&trans,&ox,&oy);
  /* cairo_translate(cr,-extents.width/2,-extents.height/2); */

  cairo_translate(r->cr,x-ox,y-oy);
  cairo_rotate(r->cr, -s->rotation);

  cairo_glyph_path(r->cr,&glyph,1);

  if (s->outlinewidth) {
    msCairoSetSourceColor(r->cr, s->outlinecolor);
    cairo_set_line_width(r->cr, s->outlinewidth + 1);
    cairo_stroke_preserve(r->cr);
  }
  if(s->color) {
    msCairoSetSourceColor(r->cr, s->color);
    cairo_fill_preserve(r->cr);
  }
  cairo_new_path(r->cr);
  cairo_restore(r->cr);
  return MS_SUCCESS;
}
Exemple #5
0
void cairo_context::glyph_path(unsigned long index, double x, double y)
{
    cairo_glyph_t glyph;
    glyph.index = index;
    glyph.x = x;
    glyph.y = y;

    cairo_glyph_path(cairo_.get(), &glyph, 1);
    check_object_status_and_throw_exception(*this);
}
Exemple #6
0
void cairo_context::glyph_path(unsigned long index, pixel_position const &pos)
{
    cairo_glyph_t glyph;
    glyph.index = index;
    glyph.x = pos.x;
    glyph.y = pos.y;

    cairo_glyph_path(cairo_.get(), &glyph, 1);
    check_object_status_and_throw_exception(*this);
}
Exemple #7
0
static int
cr_glyph_path (lua_State *L) {
    cairo_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_CONTEXT);
    cairo_glyph_t *glyphs;
    int num_glyphs;
    from_lua_glyph_array(L, &glyphs, &num_glyphs, 2);
    cairo_glyph_path(*obj, glyphs, num_glyphs);
    if (glyphs)
        GLYPHS_FREE(glyphs);
    return 1;
}
Exemple #8
0
CAMLprim value
ml_cairo_glyph_path (value v_cr, value v_glyphs)
{
  int num_glyphs;
  cairo_glyph_t *c_glyphs;
  c_glyphs = ml_convert_cairo_glypth_in (v_glyphs, &num_glyphs);
  cairo_glyph_path (cairo_t_val (v_cr), c_glyphs, num_glyphs);
  caml_stat_free (c_glyphs);
  check_cairo_status (v_cr);
  return Val_unit;
}
static VALUE
cr_glyph_path (VALUE self, VALUE rb_glyphs)
{
  int count;
  cairo_glyph_t *glyphs;

  RB_CAIRO__GLYPHS_TO_ARRAY (rb_glyphs, glyphs, count);
  cairo_glyph_path (_SELF, glyphs, count);
  cr_check_status (_SELF);

  return self;
}
TemporaryRef<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
  if (aTarget->GetType() == BACKEND_SKIA) {
    SkPaint paint;
    paint.setTypeface(GetSkTypeface());
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    paint.setTextSize(SkFloatToScalar(mSize));

    std::vector<uint16_t> indices;
    std::vector<SkPoint> offsets;
    indices.resize(aBuffer.mNumGlyphs);
    offsets.resize(aBuffer.mNumGlyphs);

    for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
      indices[i] = aBuffer.mGlyphs[i].mIndex;
      offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
      offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
    }

    SkPath path;
    paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
    return new PathSkia(path, FILL_WINDING);
  }
#endif
#ifdef USE_CAIRO
  if (aTarget->GetType() == BACKEND_CAIRO) {
    MOZ_ASSERT(mScaledFont);

    RefPtr<PathBuilder> builder_iface = aTarget->CreatePathBuilder();
    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(builder_iface.get());

    // Manually build the path for the PathBuilder.
    RefPtr<CairoPathContext> context = builder->GetPathContext();

    cairo_set_scaled_font(*context, mScaledFont);

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_glyph_path(*context, &glyphs[0], aBuffer.mNumGlyphs);

    return builder->Finish();
  }
#endif
  return NULL;
}
void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint)
{
  BackendType backendType = aBuilder->GetBackendType();
#ifdef USE_SKIA
  if (backendType == BackendType::SKIA) {
    PathBuilderSkia *builder = static_cast<PathBuilderSkia*>(aBuilder);
    builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
    return;
  }
#endif
#ifdef USE_CAIRO
  if (backendType == BackendType::CAIRO) {
    MOZ_ASSERT(mScaledFont);

    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
    cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());

    if (aTransformHint) {
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(*aTransformHint, mat);
      cairo_set_matrix(ctx, &mat);
    }

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_set_scaled_font(ctx, mScaledFont);
    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
    cairo_destroy(ctx);

    cairoPath->AppendPathToBuilder(builder);
    return;
  }
  if (backendType == BackendType::RECORDING) {
    SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
    RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
    path->StreamToSink(aBuilder);
    return;
  }
  MOZ_ASSERT(false, "Path not being copied");
#endif
}
Exemple #12
0
bool GlyphLayerShadowInset::render(
	cairo_t*       c,
	cairo_glyph_t* glyph,
	unsigned int   width,
	unsigned int   height
) {
	if(cairo_status(c) || !glyph) return false;
	
	cairo_push_group(c);
	cairo_glyph_path(c, glyph, 1);
	cairo_clip(c);
	cairo_translate(c, getOffsetX(), getOffsetY());
	// cairo_set_line_join(c, CAIRO_LINE_JOIN_ROUND);
	cairo_set_line_width(c, static_cast<double>(_radius) - 0.5f);
	cairo_glyph_path(c, glyph, 1);
	cairo_stroke(c);
	
	cairo_pattern_t* pattern = cairo_pop_group(c);
	cairo_surface_t* tmp     = createBlurredSurface(CAIRO_FORMAT_A8, pattern, width, height);

	cairo_set_source_surface(
		c,
		tmp,
		-static_cast<double>(_getBlurSize()) * 2,
		-static_cast<double>(_getBlurSize()) * 2
	);

	cairo_glyph_path(c, glyph, 1);
	cairo_clip(c);
	cairo_paint(c);

	cairo_surface_destroy(tmp);
	cairo_pattern_destroy(pattern);
	
	return true;
}
already_AddRefed<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
  if (aTarget->GetBackendType() == BackendType::SKIA) {
    SkPath path = GetSkiaPathForGlyphs(aBuffer);
    return MakeAndAddRef<PathSkia>(path, FillRule::FILL_WINDING);
  }
#endif
#ifdef USE_CAIRO
  if (aTarget->GetBackendType() == BackendType::CAIRO) {
    MOZ_ASSERT(mScaledFont);

    DrawTarget *dt = const_cast<DrawTarget*>(aTarget);
    cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));

    bool isNewContext = !ctx;
    if (!ctx) {
      ctx = cairo_create(DrawTargetCairo::GetDummySurface());
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
      cairo_set_matrix(ctx, &mat);
    }

    cairo_set_scaled_font(ctx, mScaledFont);

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_new_path(ctx);

    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> newPath = new PathCairo(ctx);
    if (isNewContext) {
      cairo_destroy(ctx);
    }

    return newPath.forget();
  }
#endif
  return nullptr;
}
Exemple #14
0
static PyObject *
pycairo_glyph_path (PycairoContext *o, PyObject *args) {
  int num_glyphs = -1;
  cairo_glyph_t *glyphs;
  PyObject *py_object;

  if (!PyArg_ParseTuple (args, "O|i:Context.glyph_path",
			 &py_object, &num_glyphs))
    return NULL;

  glyphs = _PyGlyphs_AsGlyphs (py_object, &num_glyphs);
  if (glyphs == NULL)
    return NULL;
  cairo_glyph_path (o->ctx, glyphs, num_glyphs);
  PyMem_Free (glyphs);
  RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
  Py_RETURN_NONE;
}
void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint)
{
#ifdef USE_SKIA
  if (aBackendType == BackendType::SKIA) {
    PathBuilderSkia *builder = static_cast<PathBuilderSkia*>(aBuilder);
    builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
    return;
  }
#endif
#ifdef USE_CAIRO
  if (aBackendType == BackendType::CAIRO) {
    MOZ_ASSERT(mScaledFont);

    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
    cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());

    if (aTransformHint) {
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(*aTransformHint, mat);
      cairo_set_matrix(ctx, &mat);
    }

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_set_scaled_font(ctx, mScaledFont);
    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
    cairo_destroy(ctx);

    cairoPath->AppendPathToBuilder(builder);
    return;
  }
#endif

  MOZ_CRASH("The specified backend type is not supported by CopyGlyphsToBuilder");
}
Path CairoGlyphToPathTranslator::path()
{
    Path path;
    path.ensurePlatformPath();

    cairo_glyph_t cairoGlyph;
    cairoGlyph.index = m_glyphBuffer.glyphAt(m_index);
    cairo_set_scaled_font(path.platformPath()->context(), m_fontData->platformData().scaledFont());
    cairo_glyph_path(path.platformPath()->context(), &cairoGlyph, 1);

    float syntheticBoldOffset = m_fontData->syntheticBoldOffset();
    if (syntheticBoldOffset) {
        cairo_translate(path.platformPath()->context(), syntheticBoldOffset, 0);
        cairo_show_glyphs(path.platformPath()->context(), &cairoGlyph, 1);
    }

    path.transform(m_translation);
    return path;
}
Exemple #17
0
int renderGlyphs2Cairo(imageObj *img, textPathObj *tp, colorObj *c, colorObj *oc, int ow) {
  cairo_renderer *r = CAIRO_RENDERER(img);
  cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img);
  cairoFaceCache *cairo_face = NULL;
  FT_Face prevface = NULL;
  int g;

  cairo_set_font_size(r->cr,MS_NINT(tp->glyph_size * 96.0/72.0));
  for(g=0;g<tp->numglyphs;g++) {
    glyphObj *gl = &tp->glyphs[g];
    cairo_glyph_t glyph;
    /* load the glyph's face into cairo, if not already present */
    if(gl->face->face != prevface) {
      cairo_face = getCairoFontFace(cache,gl->face->face);
      cairo_set_font_face(r->cr, cairo_face->face);
      cairo_set_font_options(r->cr,cairo_face->options);
      prevface = gl->face->face;
      cairo_set_font_size(r->cr,MS_NINT(tp->glyph_size * 96.0/72.0));
    }
    cairo_save(r->cr);
    cairo_translate(r->cr,gl->pnt.x,gl->pnt.y);
    if(gl->rot != 0.0)
      cairo_rotate(r->cr, -gl->rot);
    glyph.x = glyph.y = 0;
    glyph.index = gl->glyph->key.codepoint;
    cairo_glyph_path(r->cr,&glyph,1);
    cairo_restore(r->cr);
  }
  if (oc) {
    cairo_save(r->cr);
    msCairoSetSourceColor(r->cr, oc);
    cairo_set_line_width(r->cr, ow + 1);
    cairo_stroke_preserve(r->cr);
    cairo_restore(r->cr);
  }
  if(c) {
    msCairoSetSourceColor(r->cr, c);
    cairo_fill(r->cr);
  }
  cairo_new_path(r->cr);
  return MS_SUCCESS;
}
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    if (!font->platformData().size())
        return;

    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));

    float offset = point.x();
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i).width();
    }

    PlatformContextCairo* platformContext = context->platformContext();
    drawGlyphsShadow(context, point, font, glyphs, numGlyphs);

    cairo_t* cr = platformContext->cr();
    cairo_save(cr);

    if (context->textDrawingMode() & TextModeFill) {
        platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha);
        drawGlyphsToContext(cr, font, glyphs, numGlyphs);
    }

    // Prevent running into a long computation within cairo. If the stroke width is
    // twice the size of the width of the text we will not ask cairo to stroke
    // the text as even one single stroke would cover the full wdth of the text.
    //  See https://bugs.webkit.org/show_bug.cgi?id=33759.
    if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) {
        platformContext->prepareForStroking(context->state());
        cairo_set_line_width(cr, context->strokeThickness());

        // This may disturb the CTM, but we are going to call cairo_restore soon after.
        cairo_set_scaled_font(cr, font->platformData().scaledFont());
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_stroke(cr);
    }

    cairo_restore(cr);
}
	virtual bool render(
		cairo_t*       c,
		cairo_glyph_t* glyph,
		unsigned int   width,
		unsigned int   height
	) {
		if(cairo_status(c) || !glyph) return false;

		cairo_set_line_width(c, 1.5f);
		cairo_glyph_path(c, glyph, 1);

		cairo_pattern_t* lp = cairo_pattern_create_linear(width / 2.0f, 0.0f, width / 2.0f, height);

		cairo_pattern_add_color_stop_rgba(lp, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
		cairo_pattern_add_color_stop_rgba(lp, 0.8f, 0.0f, 1.0f, 0.0f, 0.0f);
		cairo_set_source(c, lp);
		cairo_fill(c);
		cairo_pattern_destroy(lp);

		return true;
	}
Exemple #20
0
bool GlyphLayerOutline::render(
	cairo_t*       c,
	cairo_glyph_t* glyph,
	unsigned int   width,
	unsigned int   height
) {
	if(cairo_status(c) || !glyph) return false;
	
	cairo_set_line_join(c, CAIRO_LINE_JOIN_ROUND);
	cairo_set_line_width(c, (_outline * 2) - 0.5f);
	cairo_glyph_path(c, glyph, 1);
	cairo_stroke_preserve(c);
	cairo_fill(c);

	/*
	cairo_set_operator(c, CAIRO_OPERATOR_CLEAR);
	cairo_glyph_path(c, glyph, 1);
	cairo_fill(c);
	*/

	return true;
}
Exemple #21
0
void gui_screen_t::paint() {

	g_create_thread((void*) blinkCursorThread);

	int padding = 5;
	while (true) {
		auto windowBounds = window->getBounds();
		canvas->setBounds(g_rectangle(0, 0, windowBounds.width, windowBounds.height));

		auto cr = getGraphics();
		if (cr == 0) {
			g_sleep(100);
			continue;
		}

		// clear
		cairo_save(cr);
		cairo_set_source_rgba(cr, 0, 0, 0, 1);
		cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
		cairo_paint(cr);
		cairo_restore(cr);

		// relayout text
		g_text_layouter::getInstance()->layout(cr, output.c_str(), font, 14,
				g_rectangle(padding, padding, windowBounds.width - 2 * padding - 20, windowBounds.height - 2 * padding), g_text_alignment::LEFT, viewModel,
				true);

		// check which is the lowest-down-the-screen character
		int highesty = 0;
		for (g_positioned_glyph& g : viewModel->positions) {
			int ypos = g.position.y - g.glyph->y;
			if (ypos > highesty) {
				highesty = ypos;
			}
		}

		// calculate limit
		int yLimit = windowBounds.height - 60;
		int yOffset = 0;
		if (highesty > yLimit) {
			yOffset = yLimit - highesty;
		}

		// paint characters
		g_point last;
		cairo_set_source_rgba(cr, 1, 1, 1, 1);
		for (g_positioned_glyph& g : viewModel->positions) {
			last = g.position;

			cairo_save(cr);
			cairo_translate(cr, g.position.x - g.glyph->x, yOffset + g.position.y - g.glyph->y);
			cairo_glyph_path(cr, g.glyph, g.glyph_count);
			cairo_fill(cr);
			cairo_restore(cr);
		}

		// paint cursor
		if (focused) {
			if ((g_millis() - lastInput < 300) || cursorBlink) {
				cairo_save(cr);
				cairo_set_source_rgba(cr, 1, 1, 1, 1);
				cairo_rectangle(cr, last.x + 10, yOffset + last.y - 12, 8, 14);
				cairo_fill(cr);
				cairo_restore(cr);
			}
		}

		canvas->blit(g_rectangle(0, 0, bufferSize.width, bufferSize.height));

		paint_uptodate = true;
		g_atomic_block(&paint_uptodate);
	}
}
Exemple #22
0
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
    cairo_text_extents_t extents, nil_extents;
    cairo_font_extents_t font_extents, nil_font_extents;
    cairo_scaled_font_t *scaled_font;

    cairo_select_font_face (cr, "Bitstream Vera Sans",
			    CAIRO_FONT_SLANT_NORMAL,
			    CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, 16);

    cairo_move_to (cr, 10, 25);
    cairo_show_text (cr, NULL);
    cairo_show_text (cr, "");
    cairo_show_glyphs (cr, NULL, 0);
    cairo_show_glyphs (cr, (void*)8, 0);

    cairo_move_to (cr, 10, 55);
    cairo_text_path (cr, NULL);
    cairo_text_path (cr, "");
    cairo_glyph_path (cr, (void*)8, 0);
    cairo_fill (cr);

    memset (&nil_extents, 0, sizeof (cairo_text_extents_t));

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_text_extents (cr, "", &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_text_extents(\"\"); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_text_extents (cr, NULL, &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_text_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_glyph_extents (cr, (void*)8, 0, &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_glyph_extents(); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    scaled_font = cairo_get_scaled_font (cr);

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_scaled_font_text_extents (scaled_font, "", &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_scaled_font_text_extents(\"\"); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_scaled_font_text_extents (scaled_font, NULL, &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_scaled_font_text_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_scaled_font_glyph_extents (scaled_font, (void*)8, 0, &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_scaled_font_glyph_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    /* Lets also try font size 0 while here */
    cairo_set_font_size (cr, 0);

    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
    cairo_text_extents (cr, "test", &extents);
    if (! text_extents_equal (&extents, &nil_extents)) {
	cairo_test_log (ctx, "Error: cairo_set_font_size(0); cairo_text_extents(\"test\"); extents (%g, %g, %g, %g, %g, %g)\n",
		        extents.x_bearing, extents.y_bearing,
			extents.width, extents.height,
			extents.x_advance, extents.y_advance);
	return CAIRO_TEST_FAILURE;
    }

    memset (&nil_font_extents, 0, sizeof (cairo_font_extents_t));

    memset (&font_extents, 0xff, sizeof (cairo_font_extents_t));
    cairo_font_extents (cr,  &font_extents);
    if (! font_extents_equal (&font_extents, &nil_font_extents)) {
	cairo_test_log (ctx, "Error: cairo_set_font_size(0); cairo_font_extents(); extents (%g, %g, %g, %g, %g)\n",
		        font_extents.ascent, font_extents.descent,
			font_extents.height,
			font_extents.max_x_advance, font_extents.max_y_advance);
	return CAIRO_TEST_FAILURE;
    }

    scaled_font = cairo_get_scaled_font (cr);

    memset (&font_extents, 0xff, sizeof (cairo_font_extents_t));
    cairo_scaled_font_extents (scaled_font,  &font_extents);
    if (! font_extents_equal (&font_extents, &nil_font_extents)) {
	cairo_test_log (ctx, "Error: cairo_set_font_size(0); cairo_scaled_font_extents(); extents (%g, %g, %g, %g, %g)\n",
		        font_extents.ascent, font_extents.descent,
			font_extents.height,
			font_extents.max_x_advance, font_extents.max_y_advance);
	return CAIRO_TEST_FAILURE;
    }

    return CAIRO_TEST_SUCCESS;
}
Exemple #23
0
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* cr = context->platformContext();
    cairo_save(cr);

    font->setFont(cr);

    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);

    float offset = point.x();
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i);
    }

    Color fillColor = context->fillColor();

    // Text shadow, inspired by FontMac
    IntSize shadowSize;
    int shadowBlur = 0;
    Color shadowColor;
    bool hasShadow = context->textDrawingMode() == cTextFill &&
        context->getShadow(shadowSize, shadowBlur, shadowColor);

    // TODO: Blur support
    if (hasShadow) {
        // Disable graphics context shadows (not yet implemented) and paint them manually
        context->clearShadow();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        cairo_save(cr);

        float red, green, blue, alpha;
        shadowFillColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);

        cairo_translate(cr, shadowSize.width(), shadowSize.height());
        cairo_show_glyphs(cr, glyphs, numGlyphs);

        cairo_restore(cr);
    }

    if (context->textDrawingMode() & cTextFill) {
        if (context->fillGradient()) {
            cairo_set_source(cr, context->fillGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->fillPattern()) {
            TransformationMatrix affine;
            cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine));
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else {
            float red, green, blue, alpha;
            fillColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_show_glyphs(cr, glyphs, numGlyphs);
    }

    if (context->textDrawingMode() & cTextStroke) {
        if (context->strokeGradient()) {
            cairo_set_source(cr, context->strokeGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->strokePattern()) {
            TransformationMatrix affine;
            cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine));
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else {
            Color strokeColor = context->strokeColor();
            float red, green, blue, alpha;
            strokeColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        } 
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_set_line_width(cr, context->strokeThickness());
        cairo_stroke(cr);
    }

    // Re-enable the platform shadow we disabled earlier
    if (hasShadow)
        context->setShadow(shadowSize, shadowBlur, shadowColor);

    cairo_restore(cr);
}
Exemple #24
0
int renderGlyphsCairo(imageObj *img,double x, double y, labelStyleObj *style, char *text) {
    cairo_renderer *r = CAIRO_RENDERER(img);
    cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img);
    faceCacheObj *face = getFontFace(cache,style->font);

    char *utfptr=text;
    int i,has_kerning,unicode;
    unsigned long previdx=0;
    int numglyphs = msGetNumGlyphs(text);
    cairo_glyph_t glyph;
    cairo_text_extents_t extents;
    double px=0,py=0;

    if(face == NULL) {
        return MS_FAILURE;
    }

    cairo_set_font_face(r->cr,face->face);
    cairo_set_font_size(r->cr,style->size*96/72.0);

    cairo_save(r->cr);
    cairo_translate(r->cr,MS_NINT(x),MS_NINT(y));
    if(style->rotation != 0.0)
       cairo_rotate(r->cr, -style->rotation);

    has_kerning = FT_HAS_KERNING((face->ftface));
    for(i=0;i<numglyphs;i++) {
        utfptr+=msUTF8ToUniChar(utfptr, &unicode);
        glyph.x=px;
        glyph.y=py;
        if(unicode=='\n') {
            py += ceil(style->size*CAIROLINESPACE);
            px = 0;
            previdx=0;
            continue;
        }
        glyph.index = FT_Get_Char_Index(face->ftface, unicode);
        if( has_kerning && previdx ) {
            FT_Vector delta;
            FT_Get_Kerning( face->ftface, previdx, glyph.index, FT_KERNING_DEFAULT, &delta );
            px += delta.x / 64.;
        }
        cairo_glyph_extents(r->cr,&glyph,1,&extents);
        cairo_glyph_path(r->cr,&glyph,1);
        px += extents.x_advance;
        previdx=glyph.index;
    }

    if (style->outlinewidth > 0) {
        cairo_save(r->cr);
        msCairoSetSourceColor(r->cr, style->outlinecolor);
        cairo_set_line_width(r->cr, style->outlinewidth + 1);
        cairo_stroke_preserve(r->cr);
        cairo_restore(r->cr);
    }
    if(style->color) {
        msCairoSetSourceColor(r->cr, style->color);
        cairo_fill(r->cr);
    }
    cairo_new_path(r->cr);
    cairo_restore(r->cr);
    return MS_SUCCESS;
}
TemporaryRef<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
  if (aTarget->GetType() == BACKEND_SKIA) {
    SkPaint paint;
    paint.setTypeface(GetSkTypeface());
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    paint.setTextSize(SkFloatToScalar(mSize));

    std::vector<uint16_t> indices;
    std::vector<SkPoint> offsets;
    indices.resize(aBuffer.mNumGlyphs);
    offsets.resize(aBuffer.mNumGlyphs);

    for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
      indices[i] = aBuffer.mGlyphs[i].mIndex;
      offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
      offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
    }

    SkPath path;
    paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
    return new PathSkia(path, FILL_WINDING);
  }
#endif
#ifdef USE_CAIRO
  if (aTarget->GetType() == BACKEND_CAIRO) {
    MOZ_ASSERT(mScaledFont);

    DrawTarget *dt = const_cast<DrawTarget*>(aTarget);
    cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NATIVE_SURFACE_CAIRO_CONTEXT));

    bool isNewContext = !ctx;
    if (!ctx) {
      ctx = cairo_create(DrawTargetCairo::GetDummySurface());
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
      cairo_set_matrix(ctx, &mat);
    }

    cairo_set_scaled_font(ctx, mScaledFont);

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> newPath = new PathCairo(ctx);
    if (isNewContext) {
      cairo_destroy(ctx);
    }

    return newPath;
  }
#endif
  return nullptr;
}
bool GlyphLayerDistanceField::render(
	cairo_t*       c,
	cairo_glyph_t* glyph,
	unsigned int   width,
	unsigned int   height
) {
	if(cairo_status(c) || !glyph) return false;

	unsigned int w = (width * _blockSize) + (_padding * _blockSize * 2);
	unsigned int h = (height * _blockSize) + (_padding * _blockSize * 2);

	// It distanceField needs to be square.
	if(w > h) h = w;

	else if(h > w) w = h;

	cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
	cairo_t*         cr      = cairo_create(surface);

	cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
	cairo_set_scaled_font(cr, cairo_get_scaled_font(c));
	cairo_scale(cr, _blockSize, _blockSize);
	cairo_translate(cr, _padding, _padding);
	cairo_glyph_path(cr, glyph, 1);
	cairo_fill(cr);

	cairo_surface_t* distanceField = osgPairo::createDistanceField(
		surface,
		_scanSize,
		_blockSize
	);

	// osgPairo::util::writeToPNG(distanceField, "distanceField.png");
	// osgPairo::util::writeToPNG(surface, "surface.png");

	cairo_surface_destroy(surface);
	cairo_destroy(cr);

	if(!distanceField) {
		OSG_WARN << "Unable to call osgPairo::util::createDistanceField." << std::endl;

		return false;
	}

	cairo_status_t err = cairo_surface_status(distanceField);

	if(cairo_surface_status(distanceField)) {
		OSG_WARN
			<< "Unable to call osgPairo::util::createDistanceField; error was: "
			<< cairo_status_to_string(err) << "."
			<< std::endl
		;

		return false;
	}

	cairo_set_source_surface(c, distanceField, -_padding, -_padding);
	cairo_paint(c);

	/*
	cairo_set_line_width(c, 1.0f);
	cairo_set_source_rgba(c, 1.0f, 1.0f, 1.0f, 1.0f);
	cairo_rectangle(c, -_padding + 0.5f, -_padding + 0.5f, (width + _padding * 2) - 0.5f, (height + _padding * 2) - 0.5f);
	cairo_stroke(c);
	*/

	cairo_surface_destroy(distanceField);

	return true;
}
Exemple #27
0
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* cr = context->platformContext();
    cairo_save(cr);

    cairo_set_scaled_font(cr, font->platformData().scaledFont());

    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);

    float offset = 0.0f;
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = 0.0f;
        offset += glyphBuffer.advanceAt(from + i);
    }

    Color fillColor = context->fillColor();

    // Synthetic Oblique
    if(font->platformData().syntheticOblique()) {
        cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()};
        cairo_transform(cr, &mat);
    } else {
        cairo_translate(cr, point.x(), point.y());
    }

    // Text shadow, inspired by FontMac
    FloatSize shadowOffset;
    float shadowBlur = 0;
    Color shadowColor;
    bool hasShadow = context->textDrawingMode() & cTextFill
                     && context->getShadow(shadowOffset, shadowBlur, shadowColor);

    // TODO: Blur support
    if (hasShadow) {
        // Disable graphics context shadows (not yet implemented) and paint them manually
        context->clearShadow();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        cairo_save(cr);

        float red, green, blue, alpha;
        shadowFillColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);

#if ENABLE(FILTERS)
        cairo_text_extents_t extents;
        cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);

        FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height));
        IntSize shadowBufferSize;
        FloatRect shadowRect;
        float radius = 0;
        context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur);

        // Draw shadow into a new ImageBuffer
        OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
        GraphicsContext* shadowContext = shadowBuffer->context();
        cairo_t* shadowCr = shadowContext->platformContext();

        cairo_translate(shadowCr, radius, extents.height + radius);

        cairo_set_scaled_font(shadowCr, font->platformData().scaledFont());
        cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(shadowCr);
            cairo_translate(shadowCr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
            cairo_restore(shadowCr);
        }
        cairo_translate(cr, 0.0, -extents.height);
        context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
#else
        cairo_translate(cr, shadowOffset.width(), shadowOffset.height());
        cairo_show_glyphs(cr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(cr);
            cairo_translate(cr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(cr, glyphs, numGlyphs);
            cairo_restore(cr);
        }
#endif

        cairo_restore(cr);
    }

    if (context->textDrawingMode() & cTextFill) {
        if (context->fillGradient()) {
            cairo_set_source(cr, context->fillGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->fillPattern()) {
            AffineTransform affine;
            cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine);
            cairo_set_source(cr, pattern);
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
            cairo_pattern_destroy(pattern);
        } else {
            float red, green, blue, alpha;
            fillColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_show_glyphs(cr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(cr);
            cairo_translate(cr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(cr, glyphs, numGlyphs);
            cairo_restore(cr);
        }
    }

    // Prevent running into a long computation within cairo. If the stroke width is
    // twice the size of the width of the text we will not ask cairo to stroke
    // the text as even one single stroke would cover the full wdth of the text.
    //  See https://bugs.webkit.org/show_bug.cgi?id=33759.
    if (context->textDrawingMode() & cTextStroke && context->strokeThickness() < 2 * offset) {
        if (context->strokeGradient()) {
            cairo_set_source(cr, context->strokeGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->strokePattern()) {
            AffineTransform affine;
            cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine);
            cairo_set_source(cr, pattern);
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
            cairo_pattern_destroy(pattern);
        } else {
            Color strokeColor = context->strokeColor();
            float red, green, blue, alpha;
            strokeColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_set_line_width(cr, context->strokeThickness());
        cairo_stroke(cr);
    }

    // Re-enable the platform shadow we disabled earlier
    if (hasShadow)
        context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace);

    cairo_restore(cr);
}