static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) { ShadowBlur& shadow = graphicsContext->platformContext()->shadowBlur(); if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow) return; if (!graphicsContext->mustUseShadowBlur()) { // Optimize non-blurry shadows, by just drawing text without the ShadowBlur. cairo_t* context = graphicsContext->platformContext()->cr(); cairo_save(context); FloatSize shadowOffset(graphicsContext->state().shadowOffset); cairo_translate(context, shadowOffset.width(), shadowOffset.height()); setSourceRGBAFromColor(context, graphicsContext->state().shadowColor); drawGlyphsToContext(context, font, glyphs, numGlyphs); cairo_restore(context); return; } cairo_text_extents_t extents; cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); FloatRect fontExtentsRect(point.x() + extents.x_bearing, point.y() + extents.y_bearing, extents.width, extents.height); if (GraphicsContext* shadowContext = shadow.beginShadowLayer(graphicsContext, fontExtentsRect)) { drawGlyphsToContext(shadowContext->platformContext()->cr(), font, glyphs, numGlyphs); shadow.endShadowLayer(graphicsContext); } }
void TextAttachment::SetShadow(bool enable, const Vector4& color, const Vector2& offset, const float size) { AllocateTextParameters(); if (enable != mTextParameters->mDropShadowEnabled || color != mTextParameters->mDropShadowColor || offset != mTextParameters->mDropShadow || fabsf(size - mTextParameters->mDropShadowSize) > Math::MACHINE_EPSILON_1 ) { mTextParameters->SetShadow( enable, color, offset, size ); const float unitPointSize( 64.0f ); const float unitsToPixels( mFont->GetUnitsToPixels()); const float fontPointSize( mFont->GetPointSize() ); float shadowSize( (size * 0.25f) / unitsToPixels ); Vector2 shadowOffset( offset ); Vector2 maxOffset( fontPointSize / 4.5f, fontPointSize / 4.5f ); shadowOffset = Min( shadowOffset, maxOffset ); shadowOffset = Max( shadowOffset, -maxOffset ); shadowOffset *= unitPointSize / fontPointSize; SetDropShadowMessage( mStage->GetUpdateInterface(), *mSceneObject, enable, color, shadowOffset, shadowSize ); } }
void nsTextBoxFrame::PaintOneShadow(gfxContext* aCtx, const nsRect& aTextRect, nsCSSShadowItem* aShadowDetails, const nscolor& aForegroundColor, const nsRect& aDirtyRect) { nsPoint shadowOffset(aShadowDetails->mXOffset, aShadowDetails->mYOffset); nscoord blurRadius = NS_MAX(aShadowDetails->mRadius, 0); nsRect shadowRect(aTextRect); shadowRect.MoveBy(shadowOffset); nsContextBoxBlur contextBoxBlur; gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius, PresContext()->AppUnitsPerDevPixel(), aCtx, aDirtyRect, nsnull); if (!shadowContext) return; nscolor shadowColor; if (aShadowDetails->mHasColor) shadowColor = aShadowDetails->mColor; else shadowColor = aForegroundColor; // Conjure an nsIRenderingContext from a gfxContext for DrawText nsCOMPtr<nsIRenderingContext> renderingContext = nsnull; nsIDeviceContext* devCtx = PresContext()->DeviceContext(); devCtx->CreateRenderingContextInstance(*getter_AddRefs(renderingContext)); if (!renderingContext) return; renderingContext->Init(devCtx, shadowContext); aCtx->Save(); aCtx->NewPath(); aCtx->SetColor(gfxRGBA(shadowColor)); // Draw the text onto our alpha-only surface to capture the alpha values. // Remember that the box blur context has a device offset on it, so we don't need to // translate any coordinates to fit on the surface. DrawText(*renderingContext, shadowRect, &shadowColor); contextBoxBlur.DoPaint(); aCtx->Restore(); }
static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) { do { IntSize extraOffset; if (shadow) { IntSize shadowOffset(shadow->x, shadow->y); int shadowBlur = shadow->blur; const Color& shadowColor = shadow->color; if (shadow->next || stroked) { IntRect shadowRect(x, y, w, h); shadowRect.inflate(shadowBlur); shadowRect.move(shadowOffset); context->save(); context->clip(shadowRect); extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur); shadowOffset -= extraOffset; } context->setShadow(shadowOffset, shadowBlur, shadowColor); } if (startOffset <= endOffset) context->drawText(textRun, textOrigin + extraOffset, startOffset, endOffset); else { if (endOffset > 0) context->drawText(textRun, textOrigin + extraOffset, 0, endOffset); if (startOffset < textRun.length()) context->drawText(textRun, textOrigin + extraOffset, startOffset); } if (!shadow) break; if (shadow->next || stroked) context->restore(); else context->clearShadow(); shadow = shadow->next; } while (shadow || stroked); }
ShadowApplier::ShadowApplier(GraphicsContext& context, const ShadowData* shadow, const FloatRect& textRect, bool lastShadowIterationShouldDrawText, bool opaque, FontOrientation orientation) : m_context(context) , m_shadow(shadow) , m_onlyDrawsShadow(!isLastShadowIteration() || !lastShadowIterationShouldDrawText) , m_avoidDrawingShadow(shadowIsCompletelyCoveredByText(opaque)) , m_nothingToDraw(shadow && m_avoidDrawingShadow && m_onlyDrawsShadow) , m_didSaveContext(false) { if (!shadow || m_nothingToDraw) { m_shadow = nullptr; return; } int shadowX = orientation == Horizontal ? shadow->x() : shadow->y(); int shadowY = orientation == Horizontal ? shadow->y() : -shadow->x(); FloatSize shadowOffset(shadowX, shadowY); int shadowRadius = shadow->radius(); const Color& shadowColor = shadow->color(); // When drawing shadows, we usually clip the context to the area the shadow will reside, and then // draw the text itself outside the clipped area (so only the shadow shows up). However, we can // often draw the *last* shadow and the text itself in a single call. if (m_onlyDrawsShadow) { FloatRect shadowRect(textRect); shadowRect.inflate(shadow->paintingExtent()); shadowRect.move(shadowOffset); context.save(); context.clip(shadowRect); m_didSaveContext = true; m_extraOffset = FloatSize(0, 2 * textRect.height() + std::max(0.0f, shadowOffset.height()) + shadowRadius); shadowOffset -= m_extraOffset; } if (!m_avoidDrawingShadow) context.setShadow(shadowOffset, shadowRadius, shadowColor, context.fillColorSpace()); }
void Text3D::UpdateTextMaterials(bool forceUpdate) { batches_.Resize(uiBatches_.Size()); geometries_.Resize(uiBatches_.Size()); for (unsigned i = 0; i < batches_.Size(); ++i) { if (!geometries_[i]) { Geometry* geometry = new Geometry(context_); geometry->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1); batches_[i].geometry_ = geometries_[i] = geometry; } if (!batches_[i].material_ || forceUpdate) { // If material not defined, create a reasonable default from scratch if (!material_) { Material* material = new Material(context_); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass(PASS_ALPHA); pass->SetVertexShader("Text"); pass->SetPixelShader("Text"); if (GetFont()->IsSDFFont()) { switch (GetTextEffect()) { case TE_NONE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD"); break; case TE_SHADOW: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_SHADOW"); break; case TE_STROKE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_STROKE"); break; } } pass->SetBlendMode(BLEND_ALPHA); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); batches_[i].material_ = material; } else batches_[i].material_ = material_->Clone(); } Material* material = batches_[i].material_; Texture* texture = uiBatches_[i].texture_; material->SetTexture(TU_DIFFUSE, texture); if (GetFont()->IsSDFFont()) { switch (GetTextEffect()) { case TE_SHADOW: if (texture) { Vector2 shadowOffset(0.5f / texture->GetWidth(), 0.5f / texture->GetHeight()); material->SetShaderParameter("ShadowOffset", shadowOffset); } material->SetShaderParameter("ShadowColor", GetEffectColor()); break; case TE_STROKE: material->SetShaderParameter("StrokeColor", GetEffectColor()); break; default: break; } } } }
TTFFontShadowAndStroke::TTFFontShadowAndStroke() { auto layer = LayerColor::create(Color4B(0,190,0,255)); addChild(layer, -10); auto s = Director::getInstance()->getWinSize(); Color3B tintColorRed( 255, 0, 0 ); Color3B tintColorYellow( 255, 255, 0 ); Color3B tintColorBlue( 0, 0, 255 ); Color3B strokeColor( 0, 10, 255 ); Color3B strokeShadowColor( 255, 0, 0 ); Size shadowOffset(12.0, 12.0); FontDefinition shadowTextDef; shadowTextDef._fontSize = 20; shadowTextDef._fontName = std::string("Marker Felt"); shadowTextDef._shadow._shadowEnabled = true; shadowTextDef._shadow._shadowOffset = shadowOffset; shadowTextDef._shadow._shadowOpacity = 1.0; shadowTextDef._shadow._shadowBlur = 1.0; shadowTextDef._fontFillColor = tintColorRed; // shadow only label auto fontShadow = LabelTTF::createWithFontDefinition("Shadow Only Red Text", shadowTextDef); // add label to the scene this->addChild(fontShadow); fontShadow->setPosition(Point(s.width/2,s.height/4*2.5)); // create the stroke only label FontDefinition strokeTextDef; strokeTextDef._fontSize = 20; strokeTextDef._fontName = std::string("Marker Felt"); strokeTextDef._stroke._strokeEnabled = true; strokeTextDef._stroke._strokeColor = strokeColor; strokeTextDef._stroke._strokeSize = 1.5; strokeTextDef._fontFillColor = tintColorYellow; // stroke only label auto fontStroke = LabelTTF::createWithFontDefinition("Stroke Only Yellow Text", strokeTextDef); // add label to the scene this->addChild(fontStroke); fontStroke->setPosition(Point(s.width/2,s.height/4*1.8)); // create the label stroke and shadow FontDefinition strokeShaodwTextDef; strokeShaodwTextDef._fontSize = 20; strokeShaodwTextDef._fontName = std::string("Marker Felt"); strokeShaodwTextDef._stroke._strokeEnabled = true; strokeShaodwTextDef._stroke._strokeColor = strokeShadowColor; strokeShaodwTextDef._stroke._strokeSize = 1.5; strokeShaodwTextDef._shadow._shadowEnabled = true; strokeShaodwTextDef._shadow._shadowOffset = shadowOffset; strokeShaodwTextDef._shadow._shadowOpacity = 1.0; strokeShaodwTextDef._shadow._shadowBlur = 1.0; strokeShaodwTextDef._fontFillColor = tintColorBlue; // shadow + stroke label auto fontStrokeAndShadow = LabelTTF::createWithFontDefinition("Stroke & Shadow Blue Text", strokeShaodwTextDef); // add label to the scene this->addChild(fontStrokeAndShadow); fontStrokeAndShadow->setPosition(Point(s.width/2,s.height/4*1.1)); }
void MythPainter::DrawTextPriv(MythImage *im, const QString &msg, int flags, const QRect &r, const MythFontProperties &font) { if (!im) return; QColor outlineColor; int outlineSize = 0; int outlineAlpha; if (font.hasOutline()) font.GetOutline(outlineColor, outlineSize, outlineAlpha); QPoint shadowOffset(0, 0); QColor shadowColor; int shadowAlpha; if (font.hasShadow()) font.GetShadow(shadowOffset, shadowColor, shadowAlpha); QFontMetrics fm(font.face()); int totalHeight = fm.height() + outlineSize + std::max(outlineSize, std::abs(shadowOffset.y())); // initialPaddingX is the number of pixels from the left of the // input QRect to the left of the actual text. It is always 0 // because we don't add padding to the text rectangle. int initialPaddingX = 0; // initialPaddingY is the number of pixels from the top of the // input QRect to the top of the actual text. It may be nonzero // because of extra vertical padding. int initialPaddingY = (r.height() - totalHeight) / 2; // Hack. Normally we vertically center the text due to some // (solvable) issues in the SubtitleScreen code - the text rect // and the background rect are both created with PAD_WIDTH extra // padding, and to honor Qt::AlignTop, the text rect needs to be // without padding. This doesn't work for Qt::TextWordWrap, since // the first line will be vertically centered with subsequence // lines below. So if Qt::TextWordWrap is set, we do top // alignment. if (flags & Qt::TextWordWrap) initialPaddingY = 0; // textOffsetX is the number of pixels from r.left() to the left // edge of the core text. This assumes that flags contains // Qt::AlignLeft. int textOffsetX = initialPaddingX + std::max(outlineSize, -shadowOffset.x()); // textOffsetY is the number of pixels from r.top() to the top // edge of the core text. This assumes that flags contains // Qt::AlignTop. int textOffsetY = initialPaddingY + std::max(outlineSize, -shadowOffset.y()); QImage pm(r.size(), QImage::Format_ARGB32); QColor fillcolor = font.color(); if (font.hasOutline()) fillcolor = outlineColor; fillcolor.setAlpha(0); pm.fill(fillcolor.rgba()); QPainter tmp(&pm); QFont tmpfont = font.face(); tmpfont.setStyleStrategy(QFont::OpenGLCompatible); tmp.setFont(tmpfont); QPainterPath path; if (font.hasOutline()) path.addText(0, 0, tmpfont, msg); if (font.hasShadow()) { QRect a = QRect(0, 0, r.width(), r.height()); a.translate(shadowOffset.x() + textOffsetX, shadowOffset.y() + textOffsetY); shadowColor.setAlpha(shadowAlpha); tmp.setPen(shadowColor); tmp.drawText(a, flags, msg); } if (font.hasOutline()) { // QPainter::drawText() treats the Y coordinate as the top of // the text (when Qt::AlignTop is used). However, // QPainterPath::addText() treats the Y coordinate as the base // line of the text. To translate from the top to the base // line, we need to add QFontMetrics::ascent(). int adjX = 0; int adjY = fm.ascent(); outlineColor.setAlpha(outlineAlpha); tmp.setPen(outlineColor); path.translate(adjX + textOffsetX, adjY + textOffsetY); QPen pen = tmp.pen(); pen.setWidth(outlineSize * 2 + 1); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); tmp.setPen(pen); tmp.drawPath(path); path.translate(outlineSize, outlineSize); } tmp.setPen(QPen(font.GetBrush(), 0)); tmp.setBrush(font.GetBrush()); tmp.drawText(textOffsetX, textOffsetY, r.width(), r.height(), flags, msg); tmp.end(); im->Assign(pm); }
void KoShadowConfigWidget::offsetChanged() { emit shadowOffsetChanged( shadowOffset() ); }
void Text3D::UpdateTextMaterials(bool forceUpdate) { Font* font = GetFont(); bool isSDFFont = font ? font->IsSDFFont() : false; batches_.Resize(uiBatches_.Size()); geometries_.Resize(uiBatches_.Size()); for (unsigned i = 0; i < batches_.Size(); ++i) { if (!geometries_[i]) { Geometry* geometry = new Geometry(context_); geometry->SetVertexBuffer(0, vertexBuffer_); batches_[i].geometry_ = geometries_[i] = geometry; } if (!batches_[i].material_ || forceUpdate || isSDFFont != usingSDFShader_) { // If material not defined, create a reasonable default from scratch if (!material_) { Material* material = new Material(context_); Technique* tech = new Technique(context_); Pass* pass = tech->CreatePass("alpha"); pass->SetVertexShader("Text"); pass->SetPixelShader("Text"); if (isSDFFont) { switch (GetTextEffect()) { case TE_NONE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD"); break; case TE_SHADOW: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_SHADOW"); break; case TE_STROKE: pass->SetPixelShaderDefines("SIGNED_DISTANCE_FIELD TEXT_EFFECT_STROKE"); break; } } pass->SetBlendMode(BLEND_ALPHA); pass->SetDepthWrite(false); material->SetTechnique(0, tech); material->SetCullMode(CULL_NONE); batches_[i].material_ = material; } else batches_[i].material_ = material_->Clone(); // Note: custom material is assumed to use the right kind of shader; it is not modified to define SIGNED_DISTANCE_FIELD usingSDFShader_ = isSDFFont; } Material* material = batches_[i].material_; Texture* texture = uiBatches_[i].texture_; material->SetTexture(TU_DIFFUSE, texture); if (isSDFFont) { switch (GetTextEffect()) { case TE_SHADOW: if (texture) { Vector2 shadowOffset(0.5f / texture->GetWidth(), 0.5f / texture->GetHeight()); material->SetShaderParameter("ShadowOffset", shadowOffset); } material->SetShaderParameter("ShadowColor", GetEffectColor()); break; case TE_STROKE: material->SetShaderParameter("StrokeColor", GetEffectColor()); break; default: break; } } } }
TTFFontShadowAndStroke::TTFFontShadowAndStroke() { auto layer = LayerColor::create(Color4B(0,190,0,255)); addChild(layer, -10); auto s = Director::getInstance()->getWinSize(); Color3B tintColorRed( 255, 0, 0 ); Color3B tintColorYellow( 255, 255, 0 ); Color3B tintColorBlue( 0, 0, 255 ); Color3B strokeColor( 0, 0, 255 ); Color3B strokeShadowColor( 255, 0, 0 ); Size shadowOffset(12.0, 12.0); FontDefinition shadowTextDef; shadowTextDef._fontSize = 20; shadowTextDef._fontName = std::string("Marker Felt"); shadowTextDef._shadow._shadowEnabled = true; shadowTextDef._shadow._shadowOffset = shadowOffset; shadowTextDef._shadow._shadowOpacity = 1.0; shadowTextDef._shadow._shadowBlur = 1.0; shadowTextDef._fontFillColor = tintColorRed; // shadow only label auto fontShadow = LabelTTF::createWithFontDefinition("Shadow Only Red Text", shadowTextDef); // add label to the scene this->addChild(fontShadow); fontShadow->setPosition(Vec2(s.width/2,s.height/4*2.5)); // create the stroke only label FontDefinition strokeTextDef; strokeTextDef._fontSize = 20; strokeTextDef._fontName = std::string("Marker Felt"); strokeTextDef._stroke._strokeEnabled = true; strokeTextDef._stroke._strokeColor = strokeColor; strokeTextDef._stroke._strokeSize = 1.5; strokeTextDef._fontFillColor = tintColorYellow; // stroke only label auto fontStroke = LabelTTF::createWithFontDefinition("Stroke Only Yellow Text", strokeTextDef); // add label to the scene this->addChild(fontStroke); fontStroke->setPosition(Vec2(s.width/2,s.height/4*1.8)); // create the label stroke and shadow FontDefinition strokeShaodwTextDef; strokeShaodwTextDef._fontSize = 20; strokeShaodwTextDef._fontName = std::string("Marker Felt"); strokeShaodwTextDef._stroke._strokeEnabled = true; strokeShaodwTextDef._stroke._strokeColor = strokeShadowColor; strokeShaodwTextDef._stroke._strokeSize = 1.5; strokeShaodwTextDef._shadow._shadowEnabled = true; strokeShaodwTextDef._shadow._shadowOffset = shadowOffset; strokeShaodwTextDef._shadow._shadowOpacity = 1.0; strokeShaodwTextDef._shadow._shadowBlur = 1.0; strokeShaodwTextDef._fontFillColor = tintColorBlue; // shadow + stroke label auto fontStrokeAndShadow = LabelTTF::createWithFontDefinition("Stroke & Shadow Blue Text", strokeShaodwTextDef); // add label to the scene this->addChild(fontStrokeAndShadow); fontStrokeAndShadow->setPosition(Vec2(s.width/2,s.height/4*1.1)); auto buttonBG = MenuItemImage::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png"); buttonBG->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); buttonBG->setPosition(VisibleRect::left()); // create the label stroke and shadow strokeShaodwTextDef._fontSize = 18; strokeShaodwTextDef._fontName = "Marker Felt"; strokeShaodwTextDef._stroke._strokeEnabled = true; strokeShaodwTextDef._stroke._strokeColor = Color3B::BLACK; strokeShaodwTextDef._stroke._strokeSize = 3.0f; strokeShaodwTextDef._shadow._shadowEnabled = false; strokeShaodwTextDef._shadow._shadowOffset = Size(1, 1); strokeShaodwTextDef._shadow._shadowOpacity = 1.0; strokeShaodwTextDef._shadow._shadowBlur = 0.5f; strokeShaodwTextDef._fontFillColor = Color3B::WHITE; // shadow + stroke label fontStrokeAndShadow = LabelTTF::createWithFontDefinition("Test", strokeShaodwTextDef); // add label to the scene buttonBG->addChild(fontStrokeAndShadow); fontStrokeAndShadow->setPosition(Vec2(buttonBG->getContentSize().width/2, buttonBG->getContentSize().height/2)); auto menu = Menu::create(buttonBG, nullptr); menu->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); menu->setPosition(Vec2::ZERO); addChild(menu); }