bool TextAsset::load() { // Set up a temporary Cairo surface/context for text measurement cairo_surface_t* probeSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); if (cairo_surface_status(probeSurface) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "Could not create Cairo surface\n"); _error = true; return false; } cairo_t* probeContext = cairo_create(probeSurface); if (cairo_status(probeContext) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "Could not create Cairo context\n"); _error = true; return false; } // Text rectangle drawn within border const int idealWidth = _maxSize.width - _marginLeft - _marginRight; const Size textRegion(idealWidth, _maxSize.height - _marginTop - _marginBottom); const float fontSize = primaryFontSize(probeContext, textRegion); const std::string fontDesc = _fontName + " " + boost::lexical_cast<std::string>(fontSize); PangoFontDescription* fontDescription = pango_font_description_from_string(fontDesc.c_str()); const std::string req_desc_str(pango_font_description_to_string(fontDescription)); PangoFontMap* fontMap = pango_cairo_font_map_new_for_font_type(CAIRO_FONT_TYPE_FT); PangoContext* pango_context = pango_font_map_create_context(fontMap); // TODO: Does this need to be freed or does the context take it with it? PangoFont* pangoFont = pango_font_map_load_font(fontMap, pango_context, fontDescription); PangoFontDescription* reverseDescription = pango_font_describe(pangoFont); const std::string match_desc_str(pango_font_description_to_string(reverseDescription)); pango_font_description_free(reverseDescription); g_object_unref(pango_context); if (req_desc_str.find(match_desc_str) == std::string::npos) { fprintf(stderr, "Warning: Unable to correctly match font \"%s\", using " "\"%s\" instead.\n", req_desc_str.c_str(), match_desc_str.c_str()); } float shadowXOffset = 0; float shadowYOffset = 0; if (_dropShadow) { shadowXOffset = _dropShadowOffset.x() * CLIENT_TO_SERVER_SCALE * fontSize; shadowYOffset = _dropShadowOffset.y() * CLIENT_TO_SERVER_SCALE * fontSize; } Rect tight; const Size textSize = computeSizeOfText(probeContext, _textContent, idealWidth, fontDescription, &tight); const Size imageSize = imageSizeForTextSize(tight.size, shadowXOffset, shadowYOffset); // Tear down scratch contexts cairo_destroy(probeContext); cairo_surface_destroy(probeSurface); const int width = imageSize.width; const int height = imageSize.height; // Configure the actual Cairo drawing surface/context now that we know the final resolution cairo_surface_t* cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); if (cairo_surface_status(cairoSurface) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "Could not create Cairo surface\n"); _error = true; return false; } cairo_t* cairoContext = cairo_create(cairoSurface); // Flip the context like in the iOS version. // This fixes flipped filters associated with text assets. cairo_translate(cairoContext, 0.0, height); cairo_scale(cairoContext, 1.0, -1.0); if (cairo_status(cairoContext) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "Could not create Cairo context\n"); _error = true; return false; } // Fill the box with the background color cairo_save(cairoContext); cairo_set_operator(cairoContext, CAIRO_OPERATOR_SOURCE); const mf::Color& bgColor(_style->getBackgroundColor()); cairo_set_source_rgba(cairoContext, bgColor.red, bgColor.green, bgColor.blue, bgColor.alpha); if (_shape == 0) { if (_cornerWidth > 0 && _cornerHeight > 0) { // TODO: Support independent corner width and height drawRoundedRect(cairoContext, 0, 0, imageSize.width, imageSize.height, _cornerWidth); } else { cairo_paint(cairoContext); if (_strokeThickness > 0.0f) { drawStrokedRect(cairoContext, 0, 0, imageSize.width, imageSize.height, _strokeThickness); } } } else if (_shape == 1) { strokeFillBezier(cairoContext, 0, 0, imageSize.width, imageSize.height, _strokeThickness); } cairo_restore(cairoContext); const Rect textRect = textRectForTextSize(textSize, imageSize, tight); if (_dropShadow) { const Rect shadowRect(textRect.x + shadowXOffset, textRect.y + shadowYOffset, textRect.size.width, textRect.size.height); cairo_set_source_rgba(cairoContext, _dropShadowColor.red, _dropShadowColor.green, _dropShadowColor.blue, _dropShadowColor.alpha); drawText(cairoContext, _textContent, shadowRect, fontDescription, false); } cairo_set_source_rgba(cairoContext, _textColor.red, _textColor.green, _textColor.blue, _textColor.alpha); if (_textColor.alpha > 0.0) { drawText(cairoContext, _textContent, textRect, fontDescription, true); } // DEBUG: Dump rendered text to an image // cairo_surface_write_to_png(cairoSurface, "text.png"); // Transfer Cairo surface to OpenGL texture GLubyte* imageData = static_cast<GLubyte *>(cairo_image_surface_get_data(cairoSurface)); glGenTextures(1, &_texture.textureID); glBindTexture(GL_TEXTURE_2D, _texture.textureID); _texture.width = width; _texture.height = height; _texture.s = 1.0; _texture.t = 1.0; _texture.aspect = static_cast<GLfloat>(_texture.width) / _texture.height; _texture.flipImage = true; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifdef GL_BGRA // Allocate and transfer data into texture (allow OpenGL swizzling) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, imageData); #else // Cairo uses a BGRA layout, OpenGL ES 2.0 does not support GL_BGRA as a // source format so manually perform swizzling. for (size_t i = 0; i < width * height * BYTES_PER_PIXEL; i += BYTES_PER_PIXEL) { std::swap(imageData[i], imageData[i + 2]); } // Allocate and transfer data into texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); #endif // Clean up pango_font_description_free(fontDescription); cairo_destroy(cairoContext); cairo_surface_destroy(cairoSurface); g_object_unref(pangoFont); _loading = false; _loaded = !_loading && !_error; return true; }
void po::drawStrokedRect(poRect rect) { drawStrokedRect(rect.x, rect.y, rect.width, rect.height); }
void WorldUIView::drawBorder(){ color(Color(0, 0, 0)); lineWidth(5); drawStrokedRect(Rectf(rect.x, rect.y, rect.xEnd, rect.yEnd)); }