static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const CanvasStyle& style) { if (style.canvasGradient()) return toJS(exec, globalObject, style.canvasGradient()); if (style.canvasPattern()) return toJS(exec, globalObject, style.canvasPattern()); return jsStringWithCache(exec, style.color()); }
void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/) { GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; const Font& font = accessFont(); // FIXME: Handle maxWidth. // FIXME: Need to turn off font smoothing. bool rtl = canvas()->computedStyle() ? canvas()->computedStyle()->direction() == RTL : false; bool override = canvas()->computedStyle() ? canvas()->computedStyle()->unicodeBidi() == Override : false; unsigned length = text.length(); const UChar* string = text.characters(); TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false); // Draw the item text at the correct point. FloatPoint location(x, y); switch (state().m_textBaseline) { case TopTextBaseline: case HangingTextBaseline: location.setY(y + font.ascent()); break; case BottomTextBaseline: case IdeographicTextBaseline: location.setY(y - font.descent()); break; case MiddleTextBaseline: location.setY(y - font.descent() + font.height() / 2); break; case AlphabeticTextBaseline: default: // Do nothing. break; } float width = font.width(TextRun(text, false, 0, 0, rtl, override)); TextAlign align = state().m_textAlign; if (align == StartTextAlign) align = rtl ? RightTextAlign : LeftTextAlign; else if (align == EndTextAlign) align = rtl ? LeftTextAlign : RightTextAlign; switch (align) { case CenterTextAlign: location.setX(location.x() - width / 2); break; case RightTextAlign: location.setX(location.x() - width); break; default: break; } // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text. FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(), width + font.height(), font.lineSpacing()); if (!fill) textRect.inflate(c->strokeThickness() / 2); if (fill) canvas()->willDraw(textRect); else { // When stroking text, pointy miters can extend outside of textRect, so we // punt and dirty the whole canvas. canvas()->willDraw(FloatRect(0, 0, canvas()->width(), canvas()->height())); } #if PLATFORM(CG) CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get(); if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) { // FIXME: The rect is not big enough for miters on stroked text. IntRect maskRect = enclosingIntRect(textRect); OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size()); GraphicsContext* maskImageContext = maskImage->context(); if (fill) maskImageContext->setFillColor(Color::black, DeviceColorSpace); else { maskImageContext->setStrokeColor(Color::black, DeviceColorSpace); maskImageContext->setStrokeThickness(c->strokeThickness()); } maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke); maskImageContext->translate(-maskRect.x(), -maskRect.y()); maskImageContext->drawBidiText(font, textRun, location); c->save(); c->clipToImageBuffer(maskRect, maskImage.get()); drawStyle->applyFillColor(c); c->fillRect(maskRect); c->restore(); return; } #endif c->setTextDrawingMode(fill ? cTextFill : cTextStroke); c->drawBidiText(font, textRun, location); }