1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "pxr/pxr.h"
26 
27 #include "pxr/usd/pcp/propertyIndex.h"
28 #include "pxr/usd/pcp/cache.h"
29 #include "pxr/usd/pcp/layerStack.h"
30 #include "pxr/usd/pcp/node.h"
31 #include "pxr/usd/pcp/node_Iterator.h"
32 #include "pxr/usd/pcp/pathTranslation.h"
33 #include "pxr/usd/pcp/primIndex.h"
34 #include "pxr/usd/pcp/site.h"
35 
36 #include "pxr/usd/sdf/layer.h"
37 #include "pxr/usd/sdf/listOp.h"
38 #include "pxr/usd/sdf/path.h"
39 #include "pxr/usd/sdf/attributeSpec.h"
40 #include "pxr/usd/sdf/primSpec.h"
41 #include "pxr/usd/sdf/relationshipSpec.h"
42 #include "pxr/usd/sdf/types.h"
43 #include "pxr/base/trace/trace.h"
44 #include "pxr/base/tf/token.h"
45 
46 PXR_NAMESPACE_OPEN_SCOPE
47 
48 ////////////////////////////////////////////////////////////
49 
PcpPropertyIndex()50 PcpPropertyIndex::PcpPropertyIndex()
51 {
52 }
53 
54 bool
IsEmpty() const55 PcpPropertyIndex::IsEmpty() const
56 {
57     return _propertyStack.empty();
58 }
59 
PcpPropertyIndex(const PcpPropertyIndex & rhs)60 PcpPropertyIndex::PcpPropertyIndex(const PcpPropertyIndex &rhs)
61 {
62     _propertyStack = rhs._propertyStack;
63     if (rhs._localErrors) {
64         _localErrors.reset(new PcpErrorVector(*rhs._localErrors.get()));
65     } else {
66         _localErrors.reset();
67     }
68 }
69 
70 void
Swap(PcpPropertyIndex & index)71 PcpPropertyIndex::Swap(PcpPropertyIndex& index)
72 {
73     _propertyStack.swap(index._propertyStack);
74 }
75 
76 PcpPropertyRange
GetPropertyRange(bool localOnly) const77 PcpPropertyIndex::GetPropertyRange(bool localOnly) const
78 {
79     if (localOnly) {
80         size_t startIdx = 0;
81         for (; startIdx < _propertyStack.size(); ++startIdx) {
82             if (_propertyStack[startIdx].originatingNode.IsRootNode())
83                 break;
84         }
85 
86         size_t endIdx = startIdx;
87         for (; endIdx < _propertyStack.size(); ++endIdx) {
88             if (!_propertyStack[endIdx].originatingNode.IsRootNode())
89                 break;
90         }
91 
92         const bool foundLocalSpecs = (startIdx != endIdx);
93 
94         return PcpPropertyRange(
95             PcpPropertyIterator(*this, foundLocalSpecs ? startIdx : 0),
96             PcpPropertyIterator(*this, foundLocalSpecs ? endIdx : 0));
97     }
98     else {
99         return PcpPropertyRange(
100             PcpPropertyIterator(*this, 0),
101             PcpPropertyIterator(*this, _propertyStack.size()));
102     }
103 }
104 
105 size_t
GetNumLocalSpecs() const106 PcpPropertyIndex::GetNumLocalSpecs() const
107 {
108     size_t numLocalSpecs = 0;
109     for (size_t i = 0; i < _propertyStack.size(); ++i) {
110         if (_propertyStack[i].originatingNode.IsRootNode()) {
111             ++numLocalSpecs;
112         }
113     }
114 
115     return numLocalSpecs;
116 }
117 
118 ////////////////////////////////////////////////////////////
119 
120 struct Pcp_Permissions
121 {
Pcp_PermissionsPcp_Permissions122     Pcp_Permissions()
123         : previous(SdfPermissionPublic)
124         , current(SdfPermissionPublic) { }
125 
126     SdfPermission previous;
127     SdfPermission current;
128 };
129 
130 class Pcp_PropertyIndexer
131 {
132 public:
Pcp_PropertyIndexer(PcpPropertyIndex * propIndex,PcpSite propSite,PcpErrorVector * allErrors)133     Pcp_PropertyIndexer(PcpPropertyIndex *propIndex,
134                         PcpSite propSite,
135                         PcpErrorVector *allErrors)
136         : _propIndex(propIndex),
137           _propSite(propSite),
138           _allErrors(allErrors),
139           _var(SdfVariabilityVarying),
140           _propType(SdfSpecTypeUnknown)
141     {
142     }
143 
144     void GatherPropertySpecs(const PcpPrimIndex& primIndex, bool usd);
145     void GatherRelationalAttributeSpecs( const PcpPropertyIndex& relIndex,
146                                          bool usd);
147 
148 private:
149     // Returns the property spec with the given name if it is consistent with
150     // previously seen specs, otherwise returns NULL.
151     //
_GetPrimProperty(const SdfLayerRefPtr & layer,const SdfPath & owningPrimPath,const TfToken & name,bool usd)152     SdfPropertySpecHandle _GetPrimProperty(
153         const SdfLayerRefPtr &layer,
154         const SdfPath &owningPrimPath,
155         const TfToken &name,
156         bool usd)
157     {
158         if (!layer->HasSpec(owningPrimPath))
159             return TfNullPtr;
160 
161         const SdfPath propPath = owningPrimPath.AppendProperty(name);
162         if (!layer->HasSpec(propPath))
163             return TfNullPtr;
164 
165         SdfPropertySpecHandle propSpec = layer->GetPropertyAtPath(propPath);
166         if (!propSpec)
167             return TfNullPtr;
168 
169         // See if it's an attribute.
170         const SdfSpecType propType = propSpec->GetSpecType();
171         if (_propType == SdfSpecTypeUnknown) {
172             // First one, just record the property type and layer
173             _firstSpec = propSpec;
174             _propType  = propType;
175 
176         } else if (_propType != propType) {
177             // This property spec is inconsistent with the type of the
178             // specs previously seen.
179             PcpErrorInconsistentPropertyTypePtr e =
180                 PcpErrorInconsistentPropertyType::New();
181             e->rootSite = _propSite;
182             e->definingLayerIdentifier =
183                 _firstSpec->GetLayer()->GetIdentifier();
184             e->definingSpecPath = _firstSpec->GetPath();
185             e->definingSpecType = _propType;
186             e->conflictingLayerIdentifier =
187                 propSpec->GetLayer()->GetIdentifier();
188             e->conflictingSpecPath = propSpec->GetPath();
189             e->conflictingSpecType = propType;
190             _RecordError(e);
191             return TfNullPtr;
192         }
193 
194         // For an attribute, check that its type and variability are consistent.
195         // We don't care about these mismatches in USD mode.
196         if (!usd &&
197             propType == SdfSpecTypeAttribute &&
198             !_IsConsistentAttribute(propSpec)) {
199             return TfNullPtr;
200         }
201         return propSpec;
202     }
203 
204     // Returns the attribute spec with the given name if it is consistent with
205     // previously seen specs, otherwise returns NULL.
206     //
_GetRelationalAttribute(const SdfLayerHandle & layer,const SdfPath & relAttrPath)207     SdfPropertySpecHandle _GetRelationalAttribute(
208         const SdfLayerHandle& layer,
209         const SdfPath& relAttrPath)
210     {
211         SdfPropertySpecHandle attr = layer->GetAttributeAtPath(relAttrPath);
212 
213         if (!attr)
214             return TfNullPtr;
215 
216         if (!_firstSpec) {
217             _firstSpec = attr;
218         }
219 
220         // Check that the type and variability are consistent.
221         if (!_IsConsistentAttribute(attr)) {
222             return TfNullPtr;
223         }
224         return attr;
225     }
226 
_IsConsistentAttribute(const SdfPropertySpecHandle & attr)227     bool _IsConsistentAttribute(const SdfPropertySpecHandle &attr)
228     {
229         TfToken valueType;
230         SdfVariability var = SdfVariability();
231 
232         // This function is performance sensitive, so as an optimization, get
233         // the underlying spec pointer to avoid excessive dormancy checks (one
234         // per dereference).
235         if (SdfSpec *specPtr = get_pointer(attr)) {
236             SdfLayer *layer = get_pointer(specPtr->GetLayer());
237             SdfPath const &path = specPtr->GetPath();
238             valueType = layer->GetFieldAs<TfToken>(path,
239                                                    SdfFieldKeys->TypeName);
240             var = layer->GetFieldAs<SdfVariability>(
241                 path, SdfFieldKeys->Variability);
242         }
243 
244         if (_valueType.IsEmpty()) {
245             // First one, just record the type and variability.
246             _valueType  = valueType;
247             _var        = var;
248             return true;
249         }
250 
251         if (_valueType != valueType) {
252             PcpErrorInconsistentAttributeTypePtr e =
253                 PcpErrorInconsistentAttributeType::New();
254             e->rootSite = _propSite;
255             e->definingLayerIdentifier =
256                 _firstSpec->GetLayer()->GetIdentifier();
257             e->definingSpecPath = _firstSpec->GetPath();
258             e->definingValueType = _valueType;
259             e->conflictingLayerIdentifier = attr->GetLayer()->GetIdentifier();
260             e->conflictingSpecPath = attr->GetPath();
261             e->conflictingValueType = valueType;
262             _RecordError(e);
263             return false;
264         }
265 
266         if (_var != var) {
267             PcpErrorInconsistentAttributeVariabilityPtr e =
268                 PcpErrorInconsistentAttributeVariability::New();
269             e->rootSite = _propSite;
270             e->definingLayerIdentifier =
271                 _firstSpec->GetLayer()->GetIdentifier();
272             e->definingSpecPath = _firstSpec->GetPath();
273             e->definingVariability = _var;
274             e->conflictingLayerIdentifier = attr->GetLayer()->GetIdentifier();
275             e->conflictingSpecPath = attr->GetPath();
276             e->conflictingVariability = var;
277             _RecordError(e);
278             // Not returning false here.  We will conform, not ignore.
279         }
280 
281         return true;
282     }
283 
284     // Convenience function to record an error both in this property
285     // index's local errors vector and the allErrors vector.
_RecordError(const PcpErrorBasePtr & err)286     void _RecordError(const PcpErrorBasePtr &err) {
287         _allErrors->push_back(err);
288         if (!_propIndex->_localErrors) {
289             _propIndex->_localErrors.reset(new PcpErrorVector);
290         }
291         _propIndex->_localErrors->push_back(err);
292     }
293 
294     void _AddPropertySpecIfPermitted(
295         const SdfPropertySpecHandle& propSpec,
296         const PcpNodeRef& node,
297         Pcp_Permissions* permissions,
298         std::vector<Pcp_PropertyInfo>* propertyInfo);
299 
300 private: // data
301 
302     PcpPropertyIndex *_propIndex;
303     const PcpSite _propSite;
304     PcpErrorVector *_allErrors;
305     SdfPropertySpecHandle _firstSpec;
306     TfToken _valueType;
307     SdfVariability _var;
308     SdfSpecType _propType;
309 };
310 
311 void
_AddPropertySpecIfPermitted(const SdfPropertySpecHandle & propSpec,const PcpNodeRef & node,Pcp_Permissions * permissions,std::vector<Pcp_PropertyInfo> * propertyInfo)312 Pcp_PropertyIndexer::_AddPropertySpecIfPermitted(
313     const SdfPropertySpecHandle& propSpec,
314     const PcpNodeRef& node,
315     Pcp_Permissions* permissions,
316     std::vector<Pcp_PropertyInfo>* propertyInfo)
317 {
318     if (permissions->previous == SdfPermissionPublic) {
319         // We're allowed to add this property.
320         propertyInfo->push_back(Pcp_PropertyInfo(propSpec, node));
321         // Accumulate permission.
322         permissions->current = propSpec->GetFieldAs(SdfFieldKeys->Permission,
323                                                     permissions->current);
324     } else {
325         // The previous node's property permission was private, and this
326         // node also has an opinion about it. This is illegal.
327         PcpErrorPropertyPermissionDeniedPtr err =
328             PcpErrorPropertyPermissionDenied::New();
329         err->rootSite = _propSite;
330         err->propPath = propSpec->GetPath();
331         err->propType = propSpec->GetSpecType();
332         err->layerPath = propSpec->GetLayer()->GetIdentifier();
333         _RecordError(err);
334     }
335 }
336 
337 void
GatherPropertySpecs(const PcpPrimIndex & primIndex,bool usd)338 Pcp_PropertyIndexer::GatherPropertySpecs(const PcpPrimIndex& primIndex,
339                                          bool usd)
340 {
341     const TfToken &name = _propSite.path.GetNameToken();
342 
343     // Add properties in reverse strength order (weak-to-strong).
344     std::vector<Pcp_PropertyInfo> propertyInfo;
345 
346     if (!usd) {
347         // We start with the permission from the last node we visited (or
348         // SdfPermissionPublic, if this is the first node). If the strongest
349         // opinion about the property's permission from this node is private,
350         // we are not allowed to add opinions from subsequent nodes.
351         PcpNodeRef prevNode;
352         Pcp_Permissions permissions;
353         TF_REVERSE_FOR_ALL(i, primIndex.GetPrimRange()) {
354             // Track & enforce permissions as we cross node boundaries.
355             PcpNodeRef curNode = i.base().GetNode();
356             if (curNode != prevNode) {
357                 permissions.previous = permissions.current;
358                 prevNode = curNode;
359             }
360 
361             const Pcp_SdSiteRef primSite = i.base()._GetSiteRef();
362             if (SdfPropertySpecHandle propSpec =
363                 _GetPrimProperty(primSite.layer, primSite.path, name, usd)) {
364                 _AddPropertySpecIfPermitted(
365                     propSpec, curNode, &permissions, &propertyInfo);
366             }
367         }
368 
369         // At this point, the specs have been accumulated in reverse order,
370         // because we needed to do a weak-to-strong traversal for permissions.
371         // Here, we reverse the results to give us the correct order.
372         std::reverse(propertyInfo.begin(), propertyInfo.end());
373     } else {
374         for (PcpNodeRef const& node: primIndex.GetNodeRange()) {
375             if (!node.CanContributeSpecs()) {
376                 continue;
377             }
378             SdfPath const& nodePath = node.GetPath();
379             for (SdfLayerRefPtr const& layer:
380                  node.GetLayerStack()->GetLayers()) {
381                 if (SdfPropertySpecHandle propSpec =
382                     _GetPrimProperty(layer, nodePath, name, usd)) {
383                     propertyInfo.emplace_back(propSpec, node);
384                 }
385             }
386         }
387     }
388 
389     _propIndex->_propertyStack.swap(propertyInfo);
390 }
391 
392 void
GatherRelationalAttributeSpecs(const PcpPropertyIndex & relIndex,bool usd)393 Pcp_PropertyIndexer::GatherRelationalAttributeSpecs(
394     const PcpPropertyIndex& relIndex, bool usd)
395 {
396     const SdfPath& relAttrPath = _propSite.path;
397     TF_VERIFY(relAttrPath.IsRelationalAttributePath());
398 
399     // Add relational attributes in reverse strength order (weak-to-strong).
400     std::vector<Pcp_PropertyInfo> propertyInfo;
401 
402     // We start with the permission from the last node we visited (or
403     // SdfPermissionPublic, if this is the first node). If the strongest
404     // opinion about the property's permission from this node is private,
405     // we are not allowed to add opinions from subsequent nodes.
406     Pcp_Permissions permissions;
407 
408     const PcpPropertyRange propRange = relIndex.GetPropertyRange();
409     PcpPropertyReverseIterator relIt(propRange.second);
410     const PcpPropertyReverseIterator relItEnd(propRange.first);
411 
412     while (relIt != relItEnd) {
413         const PcpNodeRef curNode = relIt.GetNode();
414 
415         const SdfPath relAttrPathInNodeNS =
416             PcpTranslatePathFromRootToNode(curNode, relAttrPath);
417 
418         for (; relIt != relItEnd && relIt.GetNode() == curNode; ++relIt) {
419             if (relAttrPathInNodeNS.IsEmpty())
420                 continue;
421 
422             const SdfPropertySpecHandle relSpec = *relIt;
423             const SdfPropertySpecHandle relAttrSpec =
424                 _GetRelationalAttribute(relSpec->GetLayer(),
425                                        relAttrPathInNodeNS);
426             if (!relAttrSpec)
427                 continue;
428 
429             if (usd) {
430                 // USD does not enforce permissions.
431                 propertyInfo.push_back(Pcp_PropertyInfo(relAttrSpec, curNode));
432             } else {
433                 _AddPropertySpecIfPermitted(
434                     relAttrSpec, curNode, &permissions, &propertyInfo);
435             }
436         }
437 
438         // Transfer this node's attribute permission.
439         permissions.previous = permissions.current;
440     }
441 
442     // At this point, the specs have been accumulated in reverse order,
443     // because we needed to do a weak-to-strong traversal for permissions.
444     // Here, we reverse the results to give us the correct order.
445     std::reverse(propertyInfo.begin(), propertyInfo.end());
446 
447     _propIndex->_propertyStack.swap(propertyInfo);
448 }
449 
PcpBuildPropertyIndex(const SdfPath & propertyPath,PcpCache * cache,PcpPropertyIndex * propertyIndex,PcpErrorVector * allErrors)450 void PcpBuildPropertyIndex( const SdfPath &propertyPath,
451                             PcpCache *cache,
452                             PcpPropertyIndex *propertyIndex,
453                             PcpErrorVector *allErrors )
454 {
455     // Verify that the given path is for a property.
456     if (!TF_VERIFY(propertyPath.IsPropertyPath())) {
457         return;
458     }
459     if (!propertyIndex->IsEmpty()) {
460         TF_CODING_ERROR("Cannot build property index for %s with a non-empty "
461                         "property stack.", propertyPath.GetText());
462         return;
463     }
464 
465     SdfPath parentPath = propertyPath.GetParentPath();
466     if (parentPath.IsTargetPath()) {
467         // Immediate parent is a target path, so this is a relational attribute.
468         // Step up one more level to the parent relationship itself.
469         parentPath = parentPath.GetParentPath();
470     }
471 
472     if (parentPath.IsPrimPath()) {
473         PcpBuildPrimPropertyIndex(
474             propertyPath,
475             *cache,
476             cache->ComputePrimIndex(parentPath, allErrors),
477             propertyIndex,
478             allErrors);
479     }
480     else if (parentPath.IsPrimPropertyPath()) {
481         const PcpSite propSite(cache->GetLayerStackIdentifier(), propertyPath);
482         Pcp_PropertyIndexer indexer(propertyIndex, propSite, allErrors);
483         // In USD mode, the PcpCache will not supply any property indexes,
484         // so we need to specifically compute one ourselves and use that.
485         //
486         // XXX: Do we need to support relational attributes in USD? Even
487         //      if the USD schema doesn't contain relational attributes,
488         //      should Pcp handle this for completeness?
489         if (cache->IsUsd()) {
490             PcpPropertyIndex relIndex;
491             PcpBuildPropertyIndex(parentPath, cache, &relIndex, allErrors);
492             indexer.GatherRelationalAttributeSpecs(relIndex, true);
493         }
494         else {
495             const PcpPropertyIndex& relIndex =
496                 cache->ComputePropertyIndex(parentPath, allErrors);
497             indexer.GatherRelationalAttributeSpecs(relIndex, false);
498         }
499     }
500     else {
501         // CODE_COVERAGE_OFF
502         // This should not happen.  Owner is not a prim or a
503         // relationship.
504         TF_CODING_ERROR(
505             "Error, the property <%s> is owned by something "
506             "that is not a prim or a relationship.",
507             propertyPath.GetText());
508         // CODE_COVERAGE_ON
509     }
510 }
511 
512 void
PcpBuildPrimPropertyIndex(const SdfPath & propertyPath,const PcpCache & cache,const PcpPrimIndex & primIndex,PcpPropertyIndex * propertyIndex,PcpErrorVector * allErrors)513 PcpBuildPrimPropertyIndex( const SdfPath& propertyPath,
514                            const PcpCache& cache,
515                            const PcpPrimIndex& primIndex,
516                            PcpPropertyIndex *propertyIndex,
517                            PcpErrorVector *allErrors )
518 {
519     const PcpSite propSite(cache.GetLayerStackIdentifier(), propertyPath);
520     Pcp_PropertyIndexer indexer(propertyIndex, propSite, allErrors);
521     indexer.GatherPropertySpecs(primIndex, cache.IsUsd());
522 }
523 
524 PXR_NAMESPACE_CLOSE_SCOPE
525