/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
using ::oox::drawingml::Color; using ::oox::drawingml::FillProperties; using ::oox::drawingml::LineArrowProperties; using ::oox::drawingml::LineProperties; using ::oox::drawingml::ShapePropertyMap; using ::com::sun::star::awt::Point; using ::com::sun::star::drawing::PolygonFlags; using ::com::sun::star::drawing::PolygonFlags_NORMAL; using ::com::sun::star::drawing::PolygonFlags_CONTROL;
namespace {
bool lclExtractDouble( double& orfValue, size_t& ornEndPos, std::u16string_view aValue )
{ // extract the double value and find start position of unit characters
rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok;
sal_Int32 nEndPos;
orfValue = ::rtl::math::stringToDouble( aValue, '.', '\0', &eConvStatus, &nEndPos );
ornEndPos = nEndPos; return eConvStatus == rtl_math_ConversionStatus_Ok;
}
bool ConversionHelper::decodeBool( std::u16string_view rValue )
{
sal_Int32 nToken = AttributeConversion::decodeToken( rValue ); // anything else than 't' or 'true' is considered to be false, as specified return (nToken == XML_t) || (nToken == XML_true);
}
// TODO: according to spec, value may contain "auto" if ( rValue == u"auto" )
{
OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - special value 'auto' must be handled by caller" ); return nRefValue;
}
// extract the double value and find start position of unit characters double fValue = 0.0;
size_t nEndPos = 0; if( !lclExtractDouble( fValue, nEndPos, rValue ) || (fValue == 0.0) ) return 0;
// process trailing unit, convert to EMU
std::u16string_view aUnit; if( (0 < nEndPos) && (nEndPos < rValue.size()) )
aUnit = rValue.substr( nEndPos ); elseif( bDefaultAsPixel )
aUnit = u"px"; // else default is EMU
// color attribute not present - set passed default color if( !roVmlColor.has_value() )
{
aDmlColor.setSrgbClr( nDefaultRgb ); return aDmlColor;
}
// separate leading color name or RGB value from following palette index
std::u16string_view aColorName, aColorIndex;
separatePair( aColorName, aColorIndex, roVmlColor.value(), ' ' );
// RGB colors in the format '#RRGGBB' if( (aColorName.size() == 7) && (aColorName[ 0 ] == '#') )
{
aDmlColor.setSrgbClr( o3tl::toUInt32(aColorName.substr( 1 ), 16) ); return aDmlColor;
}
// RGB colors in the format '#RGB' if( (aColorName.size() == 4) && (aColorName[ 0 ] == '#') )
{
sal_Int32 nR = o3tl::toUInt32(aColorName.substr( 1, 1 ), 16 ) * 0x11;
sal_Int32 nG = o3tl::toUInt32(aColorName.substr( 2, 1 ), 16 ) * 0x11;
sal_Int32 nB = o3tl::toUInt32(aColorName.substr( 3, 1 ), 16 ) * 0x11;
aDmlColor.setSrgbClr( (nR << 16) | (nG << 8) | nB ); return aDmlColor;
}
/* Predefined color names or system color names (resolve to RGB to detect
valid color name). */
sal_Int32 nColorToken = AttributeConversion::decodeToken( aColorName );
::Color nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT ); if( nRgbValue == API_RGB_TRANSPARENT )
nRgbValue = rGraphicHelper.getSystemColor( nColorToken ); if( nRgbValue != API_RGB_TRANSPARENT )
{
aDmlColor.setSrgbClr( nRgbValue ); return aDmlColor;
}
void StrokeModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
{ /* Convert VML line formatting to DrawingML line formatting and let the
DrawingML code do the hard work. */
LineProperties aLineProps;
void FillModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
{ /* Convert VML fill formatting to DrawingML fill formatting and let the
DrawingML code do the hard work. */
FillProperties aFillProps;
// type XML_gradient is linear or axial gradient if( nFillType == XML_gradient )
{ // normalize angle to range [0;360) degrees
sal_Int32 nVmlAngle = getIntervalValue< sal_Int32, sal_Int32 >( moAngle.value_or( 0 ), 0, 360 );
// focus of -50% or 50% is axial gradient // so approximate anything with a similar focus by using LO's axial gradient, // (otherwise drop the radial aspect; linear gradient becomes the closest match) if( ((-0.75 <= fFocus) && (fFocus <= -0.25)) || ((0.25 <= fFocus) && (fFocus <= 0.75)) )
{ /* According to spec, a focus of positive 50% is outer-to-inner, and -50% is inner-to-outer (color to color2). If the angle was provided as a negative,
then the colors are also (again) reversed. */ bool bOuterToInner = fFocus > 0.0; if (moAngle.value_or(0) < 0)
bOuterToInner = !bOuterToInner;
// add in order of offset
lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.0, rOuterColor);
lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.5, rInnerColor);
lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 1.0, rOuterColor);
} else// focus of -100%, 0%, and 100% is linear gradient
{ // LO linear gradients: top == start, but for MSO bottom == start == moColor bool bSwapColors = true;
/* According to spec, a focus of -100% or 100% swaps the start and stop colors, effectively reversing the gradient. If the angle was provided as a negative,
then the colors are also (again) reversed. */ if( fFocus < -0.5 || fFocus > 0.5 )
bSwapColors = !bSwapColors; if (moAngle.value_or(0) < 0)
bSwapColors = !bSwapColors;
// set the start and stop colors (focus of 0% means outer-to-inner) bool bOuterToInner = (-0.5 <= fFocus) && (fFocus <= 0.5);
lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 0.0, bOuterToInner ? aColor2 : aColor1 );
lcl_setGradientStop( aFillProps.maGradientProps.maGradientStops, 1.0, bOuterToInner ? aColor1 : aColor2 );
}
} break;
case XML_pattern: case XML_tile: case XML_frame:
{ if( moBitmapPath.has_value() && !moBitmapPath.value().isEmpty() )
{
aFillProps.maBlipProps.mxFillGraphic = rGraphicHelper.importEmbeddedGraphic(moBitmapPath.value()); if (aFillProps.maBlipProps.mxFillGraphic.is())
{ if (nFillType == XML_pattern)
{ // VML provides an 8x8 black(background) and white(foreground) pattern // along with specified background(color2) and foreground(color) colors, // while LO needs the color applied directly to the pattern. const Graphic aGraphic(aFillProps.maBlipProps.mxFillGraphic);
::Color nBackColor;
::Color nPixelColor; bool bIs8x8 = vcl::bitmap::isHistorical8x8(aGraphic.GetBitmapEx(),
nBackColor, nPixelColor); if (bIs8x8)
{
nBackColor
= ConversionHelper::decodeColor(rGraphicHelper, moColor2,
moOpacity2, API_RGB_WHITE)
.getColor(rGraphicHelper); // Documentation says undefined == white; observation says lightgray
nPixelColor
= ConversionHelper::decodeColor(rGraphicHelper, moColor,
moOpacity, COL_LIGHTGRAY)
.getColor(rGraphicHelper);
XOBitmap aXOB(aGraphic.GetBitmapEx());
aXOB.Bitmap2Array(); // LO uses the first pixel's color to represent background pixels if (aXOB.GetBackgroundColor() == COL_WHITE)
{ // White always represents the foreground in VML => swap
aXOB.SetPixelColor(nBackColor);
aXOB.SetBackgroundColor(nPixelColor);
} else
{
assert(aXOB.GetBackgroundColor() == COL_BLACK);
aXOB.SetPixelColor(nPixelColor);
aXOB.SetBackgroundColor(nBackColor);
}
aXOB.Array2Bitmap();
aFillProps.moFillType = XML_blipFill;
aFillProps.maBlipProps.moBitmapMode = (nFillType == XML_frame) ? XML_stretch : XML_tile; break; // do not break if bitmap is missing, but run to XML_solid instead
}
}
}
[[fallthrough]]; // to XML_solid in case of missing bitmap path intended!
case XML_solid: default:
{
aFillProps.moFillType = XML_solidFill; // fill color (default is white)
aFillProps.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
}
}
} else
{
aFillProps.moFillType = XML_noFill;
}
drawingml::Color aColor = ConversionHelper::decodeColor(rGraphicHelper, moColor, moOpacity, API_RGB_GRAY); // nOffset* is in mm100, default value is 35 twips, see DffPropertyReader::ApplyAttributes() in msfilter.
sal_Int32 nOffsetX = 62, nOffsetY = 62; if (moOffset.has_value())
{
std::u16string_view aOffsetX, aOffsetY;
ConversionHelper::separatePair(aOffsetX, aOffsetY, moOffset.value(), ','); if (!aOffsetX.empty())
nOffsetX = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aOffsetX, 0, false, false ); if (!aOffsetY.empty())
nOffsetY = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aOffsetY, 0, false, false );
}
table::ShadowFormat aFormat;
aFormat.Color = sal_Int32(aColor.getColor(rGraphicHelper));
aFormat.Location = nOffsetX < 0
? nOffsetY < 0 ? table::ShadowLocation_TOP_LEFT : table::ShadowLocation_BOTTOM_LEFT
: nOffsetY < 0 ? table::ShadowLocation_TOP_RIGHT : table::ShadowLocation_BOTTOM_RIGHT; // The width of the shadow is the average of the x and y values, see SwWW8ImplReader::MatchSdrItemsIntoFlySet().
aFormat.ShadowWidth = std::min<sal_Int32>(o3tl::saturating_add(std::abs(nOffsetX), std::abs(nOffsetY)) / 2, SHRT_MAX);
rPropMap.setProperty(PROP_ShadowFormat, aFormat);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.