summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Shalamov <alexander.shalamov@mapbox.com>2019-08-08 13:56:22 +0300
committerAlexander Shalamov <alexander.shalamov@mapbox.com>2019-08-20 12:31:02 +0300
commit9ba700fd47cccb3b615afae0b4b309c1e69da2f7 (patch)
tree3f788876e2a2be9d4787d81a961b660125b5546e
parent073a243862ce9634cd7db2a06aebbd3ac60a7402 (diff)
downloadqtlocation-mapboxgl-9ba700fd47cccb3b615afae0b4b309c1e69da2f7.tar.gz
[core] Fix combination of icon-text-fit with text-variable-anchors and text-writing-mode
-rw-r--r--src/mbgl/layout/symbol_instance.cpp21
-rw-r--r--src/mbgl/layout/symbol_instance.hpp7
-rw-r--r--src/mbgl/layout/symbol_layout.cpp73
-rw-r--r--src/mbgl/layout/symbol_layout.hpp2
-rw-r--r--src/mbgl/programs/symbol_program.cpp2
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp4
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp7
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp7
-rw-r--r--src/mbgl/text/placement.cpp139
-rw-r--r--src/mbgl/text/quads.cpp48
-rw-r--r--src/mbgl/text/quads.hpp4
-rw-r--r--src/mbgl/text/shaping.cpp45
-rw-r--r--src/mbgl/text/shaping.hpp7
-rw-r--r--test/text/cross_tile_symbol_index.test.cpp4
-rw-r--r--test/text/quads.test.cpp168
15 files changed, 349 insertions, 189 deletions
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 113bf5bd35..8be025afe1 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -21,15 +21,18 @@ const Shaping& getAnyShaping(const ShapedTextOrientations& shapedTextOrientation
SymbolInstanceSharedData::SymbolInstanceSharedData(GeometryCoordinates line_,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const style::SymbolLayoutProperties::Evaluated& layout,
- const float layoutTextSize,
const style::SymbolPlacementType textPlacement,
const std::array<float, 2>& textOffset,
const GlyphPositions& positions,
bool allowVerticalPlacement) : line(std::move(line_)) {
// Create the quads used for rendering the icon and glyphs.
if (shapedIcon) {
- iconQuad = getIconQuad(*shapedIcon, layout, layoutTextSize, shapedTextOrientations.horizontal);
+ iconQuad = getIconQuad(*shapedIcon, getAnyShaping(shapedTextOrientations).writingMode);
+ if (verticallyShapedIcon) {
+ verticalIconQuad = getIconQuad(*verticallyShapedIcon, shapedTextOrientations.vertical.writingMode);
+ }
}
bool singleLineInitialized = false;
@@ -69,6 +72,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
std::shared_ptr<SymbolInstanceSharedData> sharedData_,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const float textBoxScale_,
const float textPadding,
const SymbolPlacementType textPlacement,
@@ -107,6 +111,14 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
if (allowVerticalPlacement && shapedTextOrientations.vertical) {
const float verticalPointLabelAngle = 90.0f;
verticalTextCollisionFeature = CollisionFeature(line(), anchor, shapedTextOrientations.vertical, textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, textRotation + verticalPointLabelAngle);
+ if (verticallyShapedIcon) {
+ verticalIconCollisionFeature = CollisionFeature(sharedData->line,
+ anchor,
+ verticallyShapedIcon,
+ iconBoxScale, iconPadding,
+ indexedFeature,
+ iconRotation + verticalPointLabelAngle);
+ }
}
rightJustifiedGlyphQuadsSize = sharedData->rightJustifiedGlyphQuads.size();
@@ -153,6 +165,11 @@ const optional<SymbolQuad>& SymbolInstance::iconQuad() const {
return sharedData->iconQuad;
}
+const optional<SymbolQuad>& SymbolInstance::verticalIconQuad() const {
+ assert(sharedData);
+ return sharedData->verticalIconQuad;
+}
+
void SymbolInstance::releaseSharedData() {
sharedData.reset();
}
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 2c6aad653f..60883c12db 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -25,8 +25,8 @@ struct SymbolInstanceSharedData {
SymbolInstanceSharedData(GeometryCoordinates line,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const style::SymbolLayoutProperties::Evaluated& layout,
- const float layoutTextSize,
const style::SymbolPlacementType textPlacement,
const std::array<float, 2>& textOffset,
const GlyphPositions& positions,
@@ -39,6 +39,7 @@ struct SymbolInstanceSharedData {
SymbolQuads leftJustifiedGlyphQuads;
SymbolQuads verticalGlyphQuads;
optional<SymbolQuad> iconQuad;
+ optional<SymbolQuad> verticalIconQuad;
};
class SymbolInstance {
@@ -47,6 +48,7 @@ public:
std::shared_ptr<SymbolInstanceSharedData> sharedData,
const ShapedTextOrientations& shapedTextOrientations,
const optional<PositionedIcon>& shapedIcon,
+ const optional<PositionedIcon>& verticallyShapedIcon,
const float textBoxScale,
const float textPadding,
const style::SymbolPlacementType textPlacement,
@@ -71,6 +73,7 @@ public:
const SymbolQuads& centerJustifiedGlyphQuads() const;
const SymbolQuads& verticalGlyphQuads() const;
const optional<SymbolQuad>& iconQuad() const;
+ const optional<SymbolQuad>& verticalIconQuad() const;
void releaseSharedData();
private:
@@ -89,6 +92,7 @@ public:
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
optional<CollisionFeature> verticalTextCollisionFeature = nullopt;
+ optional<CollisionFeature> verticalIconCollisionFeature = nullopt;
WritingModeType writingModes;
std::size_t layoutFeatureIndex; // Index into the set of features included at layout time
std::size_t dataFeatureIndex; // Index into the underlying tile data feature set
@@ -101,6 +105,7 @@ public:
optional<size_t> placedLeftTextIndex;
optional<size_t> placedVerticalTextIndex;
optional<size_t> placedIconIndex;
+ optional<size_t> placedVerticalIconIndex;
float textBoxScale;
float radialTextOffset;
bool singleLine;
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 9459dcb716..6a13bb22ae 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -419,7 +419,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
// if either shapedText or icon position is present, add the feature
if (getDefaultHorizontalShaping(shapedTextOrientations) || shapedIcon) {
- addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositions, textOffset);
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, std::move(shapedIcon), glyphPositions, textOffset);
}
feature.geometry.clear();
@@ -431,7 +431,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const SymbolFeature& feature,
const ShapedTextOrientations& shapedTextOrientations,
- const optional<PositionedIcon>& shapedIcon,
+ optional<PositionedIcon> shapedIcon,
const GlyphPositions& glyphPositions,
Point<float> offset) {
const float minScale = 0.5f;
@@ -467,6 +467,22 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const float textRepeatDistance = symbolSpacing / 2;
const auto evaluatedLayoutProperties = layout->evaluate(zoom, feature);
IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size());
+ const bool hasIconTextFit = evaluatedLayoutProperties.get<style::IconTextFit>() != IconTextFitType::None;
+
+ // Adjust shaped icon size when icon-text-fit is used.
+ optional<PositionedIcon> verticallyShapedIcon;
+ if (shapedIcon && hasIconTextFit) {
+ // Create vertically shaped icon for vertical writing mode if needed.
+ if (allowVerticalPlacement && shapedTextOrientations.vertical) {
+ verticallyShapedIcon = shapedIcon;
+ verticallyShapedIcon->fitIconToText(evaluatedLayoutProperties,
+ shapedTextOrientations.vertical,
+ layoutTextSize);
+ }
+ shapedIcon->fitIconToText(evaluatedLayoutProperties,
+ getDefaultHorizontalShaping(shapedTextOrientations),
+ layoutTextSize);
+ }
auto addSymbolInstance = [&] (Anchor& anchor, std::shared_ptr<SymbolInstanceSharedData> sharedData) {
assert(sharedData);
@@ -478,7 +494,8 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
// In tiled rendering mode, add all symbols in the buffers so that we can:
// (1) render symbols that overlap into this tile
// (2) approximate collision detection effects from neighboring symbols
- symbolInstances.emplace_back(anchor, std::move(sharedData), shapedTextOrientations, shapedIcon,
+ symbolInstances.emplace_back(anchor, std::move(sharedData), shapedTextOrientations,
+ shapedIcon, verticallyShapedIcon,
textBoxScale, textPadding, textPlacement, textOffset,
iconBoxScale, iconPadding, iconOffset, indexedFeature,
layoutFeatureIndex, feature.index,
@@ -489,7 +506,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const auto createSymbolInstanceSharedData = [&] (GeometryCoordinates line) {
return std::make_shared<SymbolInstanceSharedData>(std::move(line),
- shapedTextOrientations, shapedIcon, evaluatedLayoutProperties, layoutTextSize,
+ shapedTextOrientations, shapedIcon, verticallyShapedIcon, evaluatedLayoutProperties,
textPlacement, textOffset, glyphPositions, allowVerticalPlacement);
};
@@ -617,6 +634,32 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
// Insert final placement into collision tree and add glyphs/icons to buffers
+ // Process icon first, so that text symbols would have reference to iconIndex which
+ // is used when dynamic vertices for icon-text-fit image have to be updated.
+ if (hasIcon) {
+ if (symbolInstance.hasIcon) {
+ const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
+ const auto placeIcon = [&] (const SymbolQuad& iconQuad, auto& index, const WritingModeType writingMode) {
+ bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
+ symbolInstance.iconOffset, writingMode, symbolInstance.line(), std::vector<float>());
+ index = bucket->icon.placedSymbols.size() - 1;
+ PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back();
+ iconSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0;
+ iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, iconQuad,
+ symbolInstance.anchor, iconSymbol, feature.sortKey);
+ };
+
+ placeIcon(*symbolInstance.iconQuad(), symbolInstance.placedIconIndex, WritingModeType::None);
+ if (symbolInstance.verticalIconQuad()) {
+ placeIcon(*symbolInstance.verticalIconQuad(), symbolInstance.placedVerticalIconIndex, WritingModeType::Vertical);
+ }
+
+ for (auto& pair : bucket->paintProperties) {
+ pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {});
+ }
+ }
+ }
+
if (hasText && feature.formattedText) {
optional<std::size_t> lastAddedSection;
if (singleLine) {
@@ -643,21 +686,6 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
updatePaintPropertiesForSection(*bucket, feature, *lastAddedSection);
}
- if (hasIcon) {
- if (symbolInstance.hasIcon) {
- const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
- bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.iconOffset, WritingModeType::None, symbolInstance.line(), std::vector<float>());
- symbolInstance.placedIconIndex = bucket->icon.placedSymbols.size() - 1;
- PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back();
- iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad(),
- symbolInstance.anchor, iconSymbol, feature.sortKey);
-
- for (auto& pair : bucket->paintProperties) {
- pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {});
- }
- }
- }
symbolInstance.releaseSharedData();
}
@@ -693,9 +721,9 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket,
optional<std::size_t> lastAddedSection) {
const Range<float> sizeData = bucket.textSizeBinder->getVertexSizeData(feature);
const bool hasFormatSectionOverrides = bucket.hasFormatSectionOverrides();
-
+ const auto& placedIconIndex = writingMode == WritingModeType::Vertical ? symbolInstance.placedVerticalIconIndex : symbolInstance.placedIconIndex;
bucket.text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.textOffset, writingMode, symbolInstance.line(), CalculateTileDistances(symbolInstance.line(), symbolInstance.anchor));
+ symbolInstance.textOffset, writingMode, symbolInstance.line(), CalculateTileDistances(symbolInstance.line(), symbolInstance.anchor), placedIconIndex);
placedIndex = bucket.text.placedSymbols.size() - 1;
PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back();
placedSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0;
@@ -837,6 +865,9 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) {
if (symbolInstance.verticalTextCollisionFeature) {
populateCollisionBox(*symbolInstance.verticalTextCollisionFeature);
}
+ if (symbolInstance.verticalIconCollisionFeature) {
+ populateCollisionBox(*symbolInstance.verticalIconCollisionFeature);
+ }
populateCollisionBox(symbolInstance.iconCollisionFeature);
}
}
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 70a3482644..6cc21c6d91 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -51,7 +51,7 @@ private:
void addFeature(const size_t,
const SymbolFeature&,
const ShapedTextOrientations& shapedTextOrientations,
- const optional<PositionedIcon>& shapedIcon,
+ optional<PositionedIcon> shapedIcon,
const GlyphPositions&,
Point<float> textOffset);
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index 3633bd7c2a..bfc0133676 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -67,7 +67,7 @@ Values makeValues(const bool isText,
const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine;
mat4 labelPlaneMatrix;
- if (alongLine || (isText && hasVariablePacement)) {
+ if (alongLine || hasVariablePacement) {
// For labels that follow lines the first part of the projection is handled on the cpu.
// Pass an identity matrix because no transformation needs to be done in the vertex shader.
matrix::identity(labelPlaneMatrix);
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 21a7870473..681a492e73 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -228,6 +228,10 @@ void SymbolBucket::sortFeatures(const float angle) {
if (symbolInstance.placedIconIndex) {
addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]);
}
+
+ if (symbolInstance.placedVerticalIconIndex) {
+ addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedVerticalIconIndex]);
+ }
}
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index f47ced8331..20c0c5b790 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -21,9 +21,9 @@ class CrossTileSymbolLayerIndex;
class PlacedSymbol {
public:
PlacedSymbol(Point<float> anchorPoint_, uint16_t segment_, float lowerSize_, float upperSize_,
- std::array<float, 2> lineOffset_, WritingModeType writingModes_, GeometryCoordinates line_, std::vector<float> tileDistances_) :
+ std::array<float, 2> lineOffset_, WritingModeType writingModes_, GeometryCoordinates line_, std::vector<float> tileDistances_, optional<size_t> placedIconIndex_ = nullopt) :
anchorPoint(anchorPoint_), segment(segment_), lowerSize(lowerSize_), upperSize(upperSize_),
- lineOffset(lineOffset_), writingModes(writingModes_), line(std::move(line_)), tileDistances(std::move(tileDistances_)), hidden(false), vertexStartIndex(0)
+ lineOffset(lineOffset_), writingModes(writingModes_), line(std::move(line_)), tileDistances(std::move(tileDistances_)), hidden(false), vertexStartIndex(0), placedIconIndex(std::move(placedIconIndex_))
{
}
Point<float> anchorPoint;
@@ -43,6 +43,9 @@ public:
// placement for orientation variants.
optional<style::TextWritingModeType> placedOrientation;
float angle = 0;
+
+ // Reference to placed icon, only applicable for text symbols.
+ optional<size_t> placedIconIndex;
};
class SymbolBucket final : public Bucket {
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index 9733241393..ffb32b9746 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -131,11 +131,12 @@ void drawIcon(const DrawFn& draw,
: gfx::TextureFilterType::Nearest };
const Size& iconSize = tile.getIconAtlasTexture().size;
+ const bool variablePlacedIcon = bucket.hasVariablePlacement && layout.get<IconTextFit>() != IconTextFitType::None;
if (bucket.sdfIcons) {
if (values.hasHalo) {
draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF,
- SymbolSDFIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
+ SymbolSDFIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
bucket.icon,
iconSegments,
bucket.iconSizeBinder,
@@ -149,7 +150,7 @@ void drawIcon(const DrawFn& draw,
if (values.hasFill) {
draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF,
- SymbolSDFIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
+ SymbolSDFIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
bucket.icon,
iconSegments,
bucket.iconSizeBinder,
@@ -162,7 +163,7 @@ void drawIcon(const DrawFn& draw,
}
} else {
draw(parameters.programs.getSymbolLayerPrograms().symbolIcon,
- SymbolIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange),
+ SymbolIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange),
bucket.icon,
iconSegments,
bucket.iconSizeBinder,
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 27c4913c63..1428cf7792 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -157,6 +157,7 @@ void Placement::placeBucket(
std::vector<style::TextVariableAnchorType> variableTextAnchors = layout.get<style::TextVariableAnchor>();
const bool rotateWithMap = layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map;
const bool pitchWithMap = layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map;
+ const bool hasIconTextFit = layout.get<style::IconTextFit>() != style::IconTextFitType::None;
const bool hasCollisionCircleData = bucket.hasCollisionCircleData();
const bool zOrderByViewportY = layout.get<style::SymbolZOrder>() == style::SymbolZOrderType::ViewportY;
@@ -179,7 +180,9 @@ void Placement::placeBucket(
bool placeIcon = false;
bool offscreen = true;
std::pair<bool, bool> placed{ false, false };
- std::pair<bool, bool> placedVertical{ false, false };
+ std::pair<bool, bool> placedVerticalText{ false, false };
+ std::pair<bool, bool> placedVerticalIcon{ false, false };
+ Point<float> shift{0.0f, 0.0f};
optional<size_t> horizontalTextIndex = symbolInstance.getDefaultHorizontalPlacedTextIndex();
if (horizontalTextIndex) {
const PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex);
@@ -200,7 +203,7 @@ void Placement::placeBucket(
assert(!bucket.placementModes.empty());
for (auto& placementMode : bucket.placementModes) {
if (placementMode == style::TextWritingModeType::Vertical) {
- placedVertical = placed = placeVerticalFn();
+ placedVerticalText = placed = placeVerticalFn();
} else {
placed = placeHorizontalFn();
}
@@ -280,7 +283,7 @@ void Placement::placeBucket(
for (size_t i = 0u; i < placementAttempts; ++i) {
auto anchor = variableTextAnchors[i % anchorsSize];
const bool allowOverlap = (i >= anchorsSize);
- Point<float> shift = calculateVariableLayoutOffset(anchor, width, height, symbolInstance.radialTextOffset, textBoxScale);
+ shift = calculateVariableLayoutOffset(anchor, width, height, symbolInstance.radialTextOffset, textBoxScale);
if (rotateWithMap) {
float angle = pitchWithMap ? state.getBearing() : -state.getBearing();
shift = util::rotate(shift, angle);
@@ -359,15 +362,28 @@ void Placement::placeBucket(
}
if (symbolInstance.placedIconIndex) {
+ if (!hasIconTextFit || !placeText || variableTextAnchors.empty()) {
+ shift = {0.0f, 0.0f};
+ }
+
const PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex);
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol);
+ const auto& placeIconFeature = [&] (const CollisionFeature& collisionFeature) {
+ return collisionIndex.placeFeature(collisionFeature, shift,
+ posMatrix, iconLabelPlaneMatrix, pixelRatio,
+ placedSymbol, scale, fontSize,
+ layout.get<style::IconAllowOverlap>(),
+ pitchWithMap,
+ params.showCollisionBoxes, avoidEdges,
+ collisionGroup.second, iconBoxes);
+ };
- auto placedIcon = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature, {},
- posMatrix, iconLabelPlaneMatrix, pixelRatio,
- placedSymbol, scale, fontSize,
- layout.get<style::IconAllowOverlap>(),
- pitchWithMap,
- params.showCollisionBoxes, avoidEdges, collisionGroup.second, iconBoxes);
+ std::pair<bool, bool> placedIcon = {false, false};
+ if (placedVerticalText.first && symbolInstance.verticalIconCollisionFeature) {
+ placedIcon = placedVerticalIcon = placeIconFeature(*symbolInstance.verticalIconCollisionFeature);
+ } else {
+ placedIcon = placeIconFeature(symbolInstance.iconCollisionFeature);
+ }
placeIcon = placedIcon.first;
offscreen &= placedIcon.second;
}
@@ -385,7 +401,7 @@ void Placement::placeBucket(
}
if (placeText) {
- if (placedVertical.first && symbolInstance.verticalTextCollisionFeature) {
+ if (placedVerticalText.first && symbolInstance.verticalTextCollisionFeature) {
collisionIndex.insertFeature(*symbolInstance.verticalTextCollisionFeature, textBoxes, layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
} else {
collisionIndex.insertFeature(symbolInstance.textCollisionFeature, textBoxes, layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
@@ -393,7 +409,11 @@ void Placement::placeBucket(
}
if (placeIcon) {
- collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ if (placedVerticalIcon.first && symbolInstance.verticalIconCollisionFeature) {
+ collisionIndex.insertFeature(*symbolInstance.verticalIconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ } else {
+ collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ }
}
if (hasCollisionCircleData) {
@@ -518,6 +538,8 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
using namespace style;
const auto& layout = *bucket.layout;
const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point;
+ const bool hasVariableAnchors = !layout.get<TextVariableAnchor>().empty() && bucket.hasTextData();
+ const bool updateTextFitIcon = layout.get<IconTextFit>() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && bucket.hasIconData();
bool result = false;
if (alongLine) {
@@ -538,7 +560,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
tile, *bucket.textSizeBinder, state);
result = true;
}
- } else if (!layout.get<TextVariableAnchor>().empty() && bucket.hasTextData()) {
+ } else if (hasVariableAnchors) {
bucket.text.dynamicVertices.clear();
bucket.hasVariablePlacement = false;
@@ -548,8 +570,10 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
const bool pitchWithMap = layout.get<TextPitchAlignment>() == AlignmentType::Map;
const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom());
const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
+ std::unordered_map<std::size_t, std::pair<std::size_t, Point<float>>> placedTextShifts;
- for (const PlacedSymbol& symbol : bucket.text.placedSymbols) {
+ for (std::size_t i = 0; i < bucket.text.placedSymbols.size(); ++i) {
+ const PlacedSymbol& symbol = bucket.text.placedSymbols[i];
optional<VariableOffset> variableOffset;
const bool skipOrientation = bucket.allowVerticalPlacement && !symbol.placedOrientation;
if (!symbol.hidden && symbol.crossTileID != 0u && !skipOrientation) {
@@ -598,24 +622,57 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
projectedAnchor.first.y + shift.y);
}
- for (std::size_t i = 0; i < symbol.glyphOffsets.size(); ++i) {
+ if (updateTextFitIcon && symbol.placedIconIndex) {
+ placedTextShifts.emplace(*symbol.placedIconIndex,
+ std::pair<std::size_t, Point<float>>{i, shiftedAnchor});
+ }
+
+ for (std::size_t j = 0; j < symbol.glyphOffsets.size(); ++j) {
addDynamicAttributes(shiftedAnchor, symbol.angle, bucket.text.dynamicVertices);
}
}
}
+ if (updateTextFitIcon && bucket.hasVariablePlacement) {
+ bucket.icon.dynamicVertices.clear();
+ for (std::size_t i = 0; i < bucket.icon.placedSymbols.size(); ++i) {
+ const PlacedSymbol& placedIcon = bucket.icon.placedSymbols[i];
+ if (placedIcon.hidden || (!placedIcon.placedOrientation && bucket.allowVerticalPlacement)) {
+ hideGlyphs(placedIcon.glyphOffsets.size(), bucket.icon.dynamicVertices);
+ } else {
+ const auto& pair = placedTextShifts.find(i);
+ if (pair == placedTextShifts.end()) {
+ hideGlyphs(placedIcon.glyphOffsets.size(), bucket.icon.dynamicVertices);
+ } else {
+ for (std::size_t j = 0; j < placedIcon.glyphOffsets.size(); ++j) {
+ addDynamicAttributes(pair->second.second, placedIcon.angle, bucket.icon.dynamicVertices);
+ }
+ }
+ }
+ }
+ }
+
result = true;
} else if (bucket.allowVerticalPlacement && bucket.hasTextData()) {
- bucket.text.dynamicVertices.clear();
- for (const PlacedSymbol& symbol : bucket.text.placedSymbols) {
- if (symbol.hidden || !symbol.placedOrientation) {
- hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices);
- } else {
- for (std::size_t i = 0; i < symbol.glyphOffsets.size(); ++i) {
- addDynamicAttributes(symbol.anchorPoint, symbol.angle, bucket.text.dynamicVertices);
+ const auto updateDynamicVertices = [](SymbolBucket::Buffer& buffer) {
+ buffer.dynamicVertices.clear();
+ for (const PlacedSymbol& symbol : buffer.placedSymbols) {
+ if (symbol.hidden || !symbol.placedOrientation) {
+ hideGlyphs(symbol.glyphOffsets.size(), buffer.dynamicVertices);
+ } else {
+ for (std::size_t j = 0; j < symbol.glyphOffsets.size(); ++j) {
+ addDynamicAttributes(symbol.anchorPoint, symbol.angle, buffer.dynamicVertices);
+ }
}
}
+ };
+
+ updateDynamicVertices(bucket.text);
+ // When text box is rotated, icon-text-fit icon must be rotated as well.
+ if (updateTextFitIcon) {
+ updateDynamicVertices(bucket.icon);
}
+
result = true;
}
@@ -635,6 +692,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
const bool variablePlacement = !bucket.layout->get<style::TextVariableAnchor>().empty();
const bool rotateWithMap = bucket.layout->get<style::TextRotationAlignment>() == style::AlignmentType::Map;
const bool pitchWithMap = bucket.layout->get<style::TextPitchAlignment>() == style::AlignmentType::Map;
+ const bool hasIconTextFit = bucket.layout->get<style::IconTextFit>() != style::IconTextFitType::None;
// If allow-overlap is true, we can show symbols before placement runs on them
// But we have to wait for placement if we potentially depend on a paired icon/text
@@ -703,25 +761,30 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
}
if (symbolInstance.hasIcon) {
const auto& opacityVertex = SymbolIconProgram::opacityVertex(opacityState.icon.placed, opacityState.icon.opacity);
- bucket.icon.opacityVertices.extend(4, opacityVertex);
if (symbolInstance.placedIconIndex) {
+ bucket.icon.opacityVertices.extend(4, opacityVertex);
bucket.icon.placedSymbols[*symbolInstance.placedIconIndex].hidden = opacityState.isHidden();
}
+
+ if (symbolInstance.placedVerticalIconIndex) {
+ bucket.icon.opacityVertices.extend(4, opacityVertex);
+ bucket.icon.placedSymbols[*symbolInstance.placedVerticalIconIndex].hidden = opacityState.isHidden();
+ }
}
- auto updateCollisionBox = [&](const auto& feature, const bool placed) {
+ auto updateCollisionBox = [&](const auto& feature, const bool placed, const Point<float>& shift) {
if (feature.alongLine) {
return;
}
- const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, {});
+ const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, shift);
bucket.collisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
};
auto updateCollisionTextBox = [this, &bucket, &symbolInstance, &state, variablePlacement, rotateWithMap, pitchWithMap](const auto& feature, const bool placed) {
+ Point<float> shift{0.0f, 0.0f};
if (feature.alongLine) {
- return;
+ return shift;
}
- Point<float> shift;
bool used = true;
if (variablePlacement) {
auto foundOffset = variableOffsets.find(symbolInstance.crossTileID);
@@ -748,6 +811,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
}
const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !used, shift);
bucket.collisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
+ return shift;
};
auto updateCollisionCircles = [&](const auto& feature, const bool placed) {
@@ -768,12 +832,17 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
};
if (bucket.hasCollisionBoxData()) {
- // TODO: update collision box opacity based on selected text variant (horizontal | vertical).
- updateCollisionTextBox(symbolInstance.textCollisionFeature, opacityState.text.placed);
- if (bucket.allowVerticalPlacement && symbolInstance.verticalTextCollisionFeature) {
- updateCollisionTextBox(*symbolInstance.verticalTextCollisionFeature, opacityState.text.placed);
+ const auto& textShift = updateCollisionTextBox(symbolInstance.textCollisionFeature, opacityState.text.placed);
+ if (bucket.allowVerticalPlacement) {
+ Point<float> verticalTextShift{0.0f, 0.0f};
+ if (symbolInstance.verticalTextCollisionFeature) {
+ verticalTextShift = updateCollisionTextBox(*symbolInstance.verticalTextCollisionFeature, opacityState.text.placed);
+ }
+ if (symbolInstance.verticalIconCollisionFeature) {
+ updateCollisionBox(*symbolInstance.verticalIconCollisionFeature, opacityState.text.placed, hasIconTextFit ? verticalTextShift : Point<float>{0.0f, 0.0f});
+ }
}
- updateCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed);
+ updateCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed, hasIconTextFit ? textShift : Point<float>{0.0f, 0.0f});
}
if (bucket.hasCollisionCircleData()) {
updateCollisionCircles(symbolInstance.textCollisionFeature, opacityState.text.placed);
@@ -850,6 +919,14 @@ void Placement::markUsedOrientation(SymbolBucket& bucket, style::TextWritingMode
if (symbolInstance.placedVerticalTextIndex) {
bucket.text.placedSymbols.at(*symbolInstance.placedVerticalTextIndex).placedOrientation = vertical;
}
+
+ if (symbolInstance.placedIconIndex) {
+ bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex).placedOrientation = horizontal;
+ }
+
+ if (symbolInstance.placedVerticalIconIndex) {
+ bucket.icon.placedSymbols.at(*symbolInstance.placedVerticalIconIndex).placedOrientation = vertical;
+ }
}
float Placement::symbolFadeChange(TimePoint now) const {
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index b08c2bc0ba..281c5d99de 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -14,9 +14,7 @@ namespace mbgl {
using namespace style;
SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
- const SymbolLayoutProperties::Evaluated& layout,
- const float layoutTextSize,
- const Shaping& shapedText) {
+ WritingModeType writingMode) {
const ImagePosition& image = shapedIcon.image();
// If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual
@@ -28,43 +26,11 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
float left = shapedIcon.left() - border / image.pixelRatio;
float bottom = shapedIcon.bottom() + border / image.pixelRatio;
float right = shapedIcon.right() + border / image.pixelRatio;
- Point<float> tl;
- Point<float> tr;
- Point<float> br;
- Point<float> bl;
-
- if (layout.get<IconTextFit>() != IconTextFitType::None && shapedText) {
- auto iconWidth = right - left;
- auto iconHeight = bottom - top;
- auto size = layoutTextSize / 24.0f;
- auto textLeft = shapedText.left * size;
- auto textRight = shapedText.right * size;
- auto textTop = shapedText.top * size;
- auto textBottom = shapedText.bottom * size;
- auto textWidth = textRight - textLeft;
- auto textHeight = textBottom - textTop;
- auto padT = layout.get<IconTextFitPadding>()[0];
- auto padR = layout.get<IconTextFitPadding>()[1];
- auto padB = layout.get<IconTextFitPadding>()[2];
- auto padL = layout.get<IconTextFitPadding>()[3];
- auto offsetY = layout.get<IconTextFit>() == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0;
- auto offsetX = layout.get<IconTextFit>() == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0;
- auto width = layout.get<IconTextFit>() == IconTextFitType::Width || layout.get<IconTextFit>() == IconTextFitType::Both ? textWidth : iconWidth;
- auto height = layout.get<IconTextFit>() == IconTextFitType::Height || layout.get<IconTextFit>() == IconTextFitType::Both ? textHeight : iconHeight;
- left = textLeft + offsetX - padL;
- top = textTop + offsetY - padT;
- right = textLeft + offsetX + padR + width;
- bottom = textTop + offsetY + padB + height;
- tl = {left, top};
- tr = {right, top};
- br = {right, bottom};
- bl = {left, bottom};
- } else {
- tl = {left, top};
- tr = {right, top};
- br = {right, bottom};
- bl = {left, bottom};
- }
+
+ Point<float> tl{left, top};
+ Point<float> tr{right, top};
+ Point<float> br{right, bottom};
+ Point<float> bl{left, bottom};
const float angle = shapedIcon.angle();
@@ -88,7 +54,7 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
static_cast<uint16_t>(image.textureRect.h + border * 2)
};
- return SymbolQuad { tl, tr, bl, br, textureRect, shapedText.writingMode, { 0.0f, 0.0f } };
+ return SymbolQuad { tl, tr, bl, br, textureRect, writingMode, { 0.0f, 0.0f } };
}
SymbolQuads getGlyphQuads(const Shaping& shapedText,
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 1ec68189af..145fd2b153 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -44,9 +44,7 @@ public:
using SymbolQuads = std::vector<SymbolQuad>;
SymbolQuad getIconQuad(const PositionedIcon& shapedIcon,
- const style::SymbolLayoutProperties::Evaluated&,
- const float layoutTextSize,
- const Shaping& shapedText);
+ WritingModeType writingMode);
SymbolQuads getGlyphQuads(const Shaping& shapedText,
const std::array<float, 2> textOffset,
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 7bf0e14f80..0cb9ea73a9 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -68,16 +68,49 @@ style::TextJustifyType getAnchorJustification(style::SymbolAnchorType anchor) {
}
}
-PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, style::SymbolAnchorType iconAnchor, const float iconRotation) {
+PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image,
+ const std::array<float, 2>& iconOffset,
+ style::SymbolAnchorType iconAnchor,
+ const float iconRotation) {
AnchorAlignment anchorAlign = AnchorAlignment::getAnchorAlignment(iconAnchor);
float dx = iconOffset[0];
float dy = iconOffset[1];
- float x1 = dx - image.displaySize()[0] * anchorAlign.horizontalAlign;
- float x2 = x1 + image.displaySize()[0];
- float y1 = dy - image.displaySize()[1] * anchorAlign.verticalAlign;
- float y2 = y1 + image.displaySize()[1];
+ float left = dx - image.displaySize()[0] * anchorAlign.horizontalAlign;
+ float right = left + image.displaySize()[0];
+ float top = dy - image.displaySize()[1] * anchorAlign.verticalAlign;
+ float bottom = top + image.displaySize()[1];
- return PositionedIcon { image, y1, y2, x1, x2, iconRotation };
+ return PositionedIcon { image, top, bottom, left, right, iconRotation };
+}
+
+void PositionedIcon::fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout,
+ const Shaping& shapedText,
+ float layoutTextSize) {
+ using namespace style;
+ assert(layout.get<IconTextFit>() != IconTextFitType::None);
+ if (shapedText) {
+ auto iconWidth = _right - _left;
+ auto iconHeight = _bottom - _top;
+ auto size = layoutTextSize / 24.0f;
+ auto textLeft = shapedText.left * size;
+ auto textRight = shapedText.right * size;
+ auto textTop = shapedText.top * size;
+ auto textBottom = shapedText.bottom * size;
+ auto textWidth = textRight - textLeft;
+ auto textHeight = textBottom - textTop;
+ auto padT = layout.get<IconTextFitPadding>()[0];
+ auto padR = layout.get<IconTextFitPadding>()[1];
+ auto padB = layout.get<IconTextFitPadding>()[2];
+ auto padL = layout.get<IconTextFitPadding>()[3];
+ auto offsetY = layout.get<IconTextFit>() == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0;
+ auto offsetX = layout.get<IconTextFit>() == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0;
+ auto width = layout.get<IconTextFit>() == IconTextFitType::Width || layout.get<IconTextFit>() == IconTextFitType::Both ? textWidth : iconWidth;
+ auto height = layout.get<IconTextFit>() == IconTextFitType::Height || layout.get<IconTextFit>() == IconTextFitType::Both ? textHeight : iconHeight;
+ _left = textLeft + offsetX - padL;
+ _top = textTop + offsetY - padT;
+ _right = textLeft + offsetX + padR + width;
+ _bottom = textTop + offsetY + padB + height;
+ }
}
void align(Shaping& shaping,
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index f3a01e3caf..60a9c718ff 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -4,6 +4,7 @@
#include <mbgl/text/tagged_string.hpp>
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
namespace mbgl {
@@ -52,6 +53,12 @@ public:
style::SymbolAnchorType iconAnchor,
const float iconRotation);
+ // Updates shaped icon's bounds based on shaped text's bounds and provided
+ // layout properties.
+ void fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout,
+ const Shaping& shapedText,
+ float layoutTextSize);
+
const ImagePosition& image() const { return _image; }
float top() const { return _top; }
float bottom() const { return _bottom; }
diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp
index ccf83e81c8..a1385dfa8a 100644
--- a/test/text/cross_tile_symbol_index.test.cpp
+++ b/test/text/cross_tile_symbol_index.test.cpp
@@ -16,9 +16,9 @@ SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) {
style::SymbolPlacementType placementType = style::SymbolPlacementType::Point;
auto sharedData = std::make_shared<SymbolInstanceSharedData>(std::move(line),
- shaping, nullopt, layout_, 0.0f, placementType,
+ shaping, nullopt, nullopt, layout_, placementType,
textOffset, positions, false);
- return SymbolInstance(anchor, std::move(sharedData), shaping, nullopt, 0, 0, placementType, textOffset, 0, 0, iconOffset, subfeature, 0, 0, key, 0.0f, 0.0f, 0.0f, 0.0f, false);
+ return SymbolInstance(anchor, std::move(sharedData), shaping, nullopt, nullopt, 0, 0, placementType, textOffset, 0, 0, iconOffset, subfeature, 0, 0, key, 0.0f, 0.0f, 0.0f, 0.0f, false);
}
diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp
index c032d58b88..7aaeb4870d 100644
--- a/test/text/quads.test.cpp
+++ b/test/text/quads.test.cpp
@@ -20,10 +20,9 @@ TEST(getIconQuads, normal) {
auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -6.5f, -4.5f }}, SymbolAnchorType::Center, 0);
GeometryCoordinates line;
- Shaping shapedText;
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 16.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
EXPECT_EQ(quad.tl.x, -14);
EXPECT_EQ(quad.tl.y, -10);
@@ -42,8 +41,6 @@ TEST(getIconQuads, style) {
style::Image::Impl("test", PremultipliedImage({1,1}), 1.0)
};
- auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
-
GeometryCoordinates line;
Shaping shapedText;
shapedText.top = -10.0f;
@@ -54,9 +51,10 @@ TEST(getIconQuads, style) {
// none
{
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
SymbolLayoutProperties::Evaluated layout;
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
EXPECT_EQ(quad.tl.x, -19.5);
EXPECT_EQ(quad.tl.y, -19.5);
@@ -73,16 +71,18 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 24.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 24.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
- EXPECT_EQ(quad.tl.x, -60);
+ EXPECT_EQ(quad.tl.x, -61);
EXPECT_EQ(quad.tl.y, 0);
- EXPECT_EQ(quad.tr.x, 20);
+ EXPECT_EQ(quad.tr.x, 21);
EXPECT_EQ(quad.tr.y, 0);
- EXPECT_EQ(quad.bl.x, -60);
+ EXPECT_EQ(quad.bl.x, -61);
EXPECT_EQ(quad.bl.y, 20);
- EXPECT_EQ(quad.br.x, 20);
+ EXPECT_EQ(quad.br.x, 21);
EXPECT_EQ(quad.br.y, 20);
}
@@ -91,16 +91,18 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
- EXPECT_EQ(quad.tl.x, -30);
+ EXPECT_EQ(quad.tl.x, -31);
EXPECT_EQ(quad.tl.y, -5);
- EXPECT_EQ(quad.tr.x, 10);
+ EXPECT_EQ(quad.tr.x, 11);
EXPECT_EQ(quad.tr.y, -5);
- EXPECT_EQ(quad.bl.x, -30);
+ EXPECT_EQ(quad.bl.x, -31);
EXPECT_EQ(quad.bl.y, 15);
- EXPECT_EQ(quad.br.x, 10);
+ EXPECT_EQ(quad.br.x, 11);
EXPECT_EQ(quad.br.y, 15);
}
@@ -113,16 +115,18 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 10.0f;
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
- EXPECT_EQ(quad.tl.x, -40);
+ EXPECT_EQ(quad.tl.x, -41);
EXPECT_EQ(quad.tl.y, -10);
- EXPECT_EQ(quad.tr.x, 20);
+ EXPECT_EQ(quad.tr.x, 21);
EXPECT_EQ(quad.tr.y, -10);
- EXPECT_EQ(quad.bl.x, -40);
+ EXPECT_EQ(quad.bl.x, -41);
EXPECT_EQ(quad.bl.y, 20);
- EXPECT_EQ(quad.br.x, 20);
+ EXPECT_EQ(quad.br.x, 21);
EXPECT_EQ(quad.br.y, 20);
}
@@ -131,17 +135,19 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 24.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 24.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
EXPECT_EQ(quad.tl.x, -30);
- EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tl.y, -11);
EXPECT_EQ(quad.tr.x, -10);
- EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.tr.y, -11);
EXPECT_EQ(quad.bl.x, -30);
- EXPECT_EQ(quad.bl.y, 30);
+ EXPECT_EQ(quad.bl.y, 31);
EXPECT_EQ(quad.br.x, -10);
- EXPECT_EQ(quad.br.y, 30);
+ EXPECT_EQ(quad.br.y, 31);
}
// height x textSize
@@ -149,17 +155,19 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
EXPECT_EQ(quad.tl.x, -20);
- EXPECT_EQ(quad.tl.y, -5);
+ EXPECT_EQ(quad.tl.y, -6);
EXPECT_EQ(quad.tr.x, 0);
- EXPECT_EQ(quad.tr.y, -5);
+ EXPECT_EQ(quad.tr.y, -6);
EXPECT_EQ(quad.bl.x, -20);
- EXPECT_EQ(quad.bl.y, 15);
+ EXPECT_EQ(quad.bl.y, 16);
EXPECT_EQ(quad.br.x, 0);
- EXPECT_EQ(quad.br.y, 15);
+ EXPECT_EQ(quad.br.y, 16);
}
// height x textSize + padding
@@ -171,17 +179,19 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 10.0f;
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
EXPECT_EQ(quad.tl.x, -30);
- EXPECT_EQ(quad.tl.y, -10);
+ EXPECT_EQ(quad.tl.y, -11);
EXPECT_EQ(quad.tr.x, 10);
- EXPECT_EQ(quad.tr.y, -10);
+ EXPECT_EQ(quad.tr.y, -11);
EXPECT_EQ(quad.bl.x, -30);
- EXPECT_EQ(quad.bl.y, 20);
+ EXPECT_EQ(quad.bl.y, 21);
EXPECT_EQ(quad.br.x, 10);
- EXPECT_EQ(quad.br.y, 20);
+ EXPECT_EQ(quad.br.y, 21);
}
// both
@@ -189,17 +199,19 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 24.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 24.0f, shapedText);
-
- EXPECT_EQ(quad.tl.x, -60);
- EXPECT_EQ(quad.tl.y, -10);
- EXPECT_EQ(quad.tr.x, 20);
- EXPECT_EQ(quad.tr.y, -10);
- EXPECT_EQ(quad.bl.x, -60);
- EXPECT_EQ(quad.bl.y, 30);
- EXPECT_EQ(quad.br.x, 20);
- EXPECT_EQ(quad.br.y, 30);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
+
+ EXPECT_EQ(quad.tl.x, -61);
+ EXPECT_EQ(quad.tl.y, -11);
+ EXPECT_EQ(quad.tr.x, 21);
+ EXPECT_EQ(quad.tr.y, -11);
+ EXPECT_EQ(quad.bl.x, -61);
+ EXPECT_EQ(quad.bl.y, 31);
+ EXPECT_EQ(quad.br.x, 21);
+ EXPECT_EQ(quad.br.y, 31);
}
// both x textSize
@@ -207,17 +219,19 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
-
- EXPECT_EQ(quad.tl.x, -30);
- EXPECT_EQ(quad.tl.y, -5);
- EXPECT_EQ(quad.tr.x, 10);
- EXPECT_EQ(quad.tr.y, -5);
- EXPECT_EQ(quad.bl.x, -30);
- EXPECT_EQ(quad.bl.y, 15);
- EXPECT_EQ(quad.br.x, 10);
- EXPECT_EQ(quad.br.y, 15);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
+
+ EXPECT_EQ(quad.tl.x, -31);
+ EXPECT_EQ(quad.tl.y, -6);
+ EXPECT_EQ(quad.tr.x, 11);
+ EXPECT_EQ(quad.tr.y, -6);
+ EXPECT_EQ(quad.bl.x, -31);
+ EXPECT_EQ(quad.bl.y, 16);
+ EXPECT_EQ(quad.br.x, 11);
+ EXPECT_EQ(quad.br.y, 16);
}
// both x textSize + padding
@@ -229,17 +243,19 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 10.0f;
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
-
- EXPECT_EQ(quad.tl.x, -40);
- EXPECT_EQ(quad.tl.y, -10);
- EXPECT_EQ(quad.tr.x, 20);
- EXPECT_EQ(quad.tr.y, -10);
- EXPECT_EQ(quad.bl.x, -40);
- EXPECT_EQ(quad.bl.y, 20);
- EXPECT_EQ(quad.br.x, 20);
- EXPECT_EQ(quad.br.y, 20);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
+
+ EXPECT_EQ(quad.tl.x, -41);
+ EXPECT_EQ(quad.tl.y, -11);
+ EXPECT_EQ(quad.tr.x, 21);
+ EXPECT_EQ(quad.tr.y, -11);
+ EXPECT_EQ(quad.bl.x, -41);
+ EXPECT_EQ(quad.bl.y, 21);
+ EXPECT_EQ(quad.br.x, 21);
+ EXPECT_EQ(quad.br.y, 21);
}
// both x textSize + padding t/r/b/l
@@ -251,17 +267,19 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 5.0f;
layout.get<IconTextFitPadding>()[2] = 10.0f;
layout.get<IconTextFitPadding>()[3] = 15.0f;
+ auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0);
+ shapedIcon.fitIconToText(layout, shapedText, 12.0f);
SymbolQuad quad =
- getIconQuad(shapedIcon, layout, 12.0f, shapedText);
-
- EXPECT_EQ(quad.tl.x, -45);
- EXPECT_EQ(quad.tl.y, -5);
- EXPECT_EQ(quad.tr.x, 15);
- EXPECT_EQ(quad.tr.y, -5);
- EXPECT_EQ(quad.bl.x, -45);
- EXPECT_EQ(quad.bl.y, 25);
- EXPECT_EQ(quad.br.x, 15);
- EXPECT_EQ(quad.br.y, 25);
+ getIconQuad(shapedIcon, WritingModeType::Horizontal);
+
+ EXPECT_EQ(quad.tl.x, -46);
+ EXPECT_EQ(quad.tl.y, -6);
+ EXPECT_EQ(quad.tr.x, 16);
+ EXPECT_EQ(quad.tr.y, -6);
+ EXPECT_EQ(quad.bl.x, -46);
+ EXPECT_EQ(quad.bl.y, 26);
+ EXPECT_EQ(quad.br.x, 16);
+ EXPECT_EQ(quad.br.y, 26);
}
}